Introduction
In this notebook we demonstrate how to use Milo to detect abherrant cell states in diseased tissues, using a dataset of hepatic non-parenchymal cells isolated from 5 healthy and 5 cirrhotic human livers. Ramachandran et al. 2019 (GEO accessiion: GSE136103).
suppressPackageStartupMessages({
library(tidyverse)
library(irlba)
library(DropletUtils)
library(scater)
library(scran)
library(Seurat) ## just 4 loading the object
library(miloR)
library(SingleCellExperiment)
library(patchwork)
library(igraph)
library(RColorBrewer)
library(cowplot)
})
Load data
We downloaded the dataset and annotations stored in Seurat object from here, as indicated by the authors.
load("/nfs/team205/ed6/data/Ramachandran2019_liver/tissue.rdata")
## Convert to SingleCellExperiment
liver_sce <- SingleCellExperiment(assay = list(counts=tissue@raw.data, logcounts=tissue@data),
colData = tissue@meta.data)
liver_sce
class: SingleCellExperiment
dim: 23498 58358
metadata(0):
assays(2): counts logcounts
rownames(23498): FO538757.2 AP006222.2 ... CTA-126B4.7 LINC01423
rowData names(0):
colnames(58358): Healthy1_Cd45+_AAACCTGCAGTATCTG
Healthy1_Cd45+_AACTGGTTCATGGTCA ...
Cirrhotic3_Cd45-_TTTGTCATCCAGGGCT
Cirrhotic3_Cd45-_TCTGGAAGTCATCCCT
colData names(10): nGene nUMI ... annotation_indepth
annotation_lineage
reducedDimNames(0):
spikeNames(0):
altExpNames(0):
Preprocessing
Feature selection
dec_liver <- modelGeneVar(liver_sce)
fit_liver <- metadata(dec_liver)
plot(fit_liver$mean, fit_liver$var, xlab="Mean of log-expression",
ylab="Variance of log-expression")

hvgs <- getTopHVGs(dec_liver, n=3000)
Dimensionality reduction with PCA
liver_sce <- runPCA(liver_sce, subset_row=hvgs, ncomponents=11)
plotPCA(liver_sce, colour_by="condition", ncomponents=3)

liver_sce <- runUMAP(liver_sce, dimred="PCA", ncomponents=2)
scater::plotUMAP(liver_sce, colour_by="condition", point_alpha=1, point_size=0.5)

scater::plotUMAP(liver_sce, colour_by="dataset", point_alpha=0.3, point_size=0.5)

scater::plotUMAP(liver_sce, colour_by="annotation_lineage", point_alpha=0.3, point_size=0.5, text_by='annotation_lineage')

# scater::plotUMAP(liver_sce, colour_by='annotation_indepth', point_alpha=0.3, point_size=0.5, text_by='annotation_indepth')
Notably, this dataset doesn’t appear to display a batch effect
DA analysis with Milo
We test for differential abundance between healthy and cirrhotic livers. We start by defining neighbourhoods with refined sampling on the KNN graph. We inspect the size of neighbourhoods.
liver_milo <- Milo(liver_sce)
## Build KNN graph
liver_milo <- buildGraph(liver_milo, d = 11, k=30)
Constructing kNN graph with k:30
## Compute neighbourhoods with refined sampling
liver_milo <- makeNhoods(liver_milo, k=30, d=11, prop = 0.05, refined=TRUE)
Checking valid object
plotNhoodSizeHist(liver_milo, bins=150)

Then we make a design matrix for the differential test, assigning samples to conditions.
liver_meta <- as.tibble(colData(liver_milo)[,c("dataset","condition")])
`as.tibble()` is deprecated as of tibble 2.0.0.
Please use `as_tibble()` instead.
The signature and semantics have changed, see `?as_tibble`.
[90mThis warning is displayed once every 8 hours.[39m
[90mCall `lifecycle::last_warnings()` to see where this warning was generated.[39m
liver_meta <- distinct(liver_meta) %>%
mutate(condition=factor(condition, levels=c("Uninjured", "Cirrhotic"))) %>%
column_to_rownames("dataset")
Now we can count cells in neighbourhoods and perform the DA test.
liver_milo <- countCells(liver_milo, samples = "dataset", meta.data = data.frame(colData(liver_milo)[,c("dataset","condition")]) )
Checking meta.data validity
Setting up matrix with 2717 neighbourhoods
Counting cells in neighbourhoods
liver_milo <- calcNhoodDistance(liver_milo, d=11)
milo_res <- testNhoods(liver_milo, design = ~ condition, design.df = liver_meta, fdr.weighting = "k-distance")
Performing spatial FDR correction withk-distance weighting
Exploration of DA results
We can start by looking at some basic stats
pval_hist <- milo_res %>%
ggplot(aes(PValue)) +
geom_histogram(bins=50) +
theme_bw(base_size=14)
volcano <-
milo_res %>%
ggplot(aes(logFC, -log10(SpatialFDR))) +
geom_point(size=0.4, alpha=0.2) +
geom_hline(yintercept = -log10(0.1)) +
xlab("log-Fold Change") +
theme_bw(base_size=14)
pval_hist + volcano

The distribution of P-values looks sensible and from the volcano plot we can see that we have identified some DA neighbourhoods at 10% FDR. We can visualize DA neighbourhoods building an abstracted graph
liver_milo <- buildNhoodGraph(liver_milo)
Calculating nhood adjacency
\
Error: unexpected input in "\"
## Save milo object and results
saveRDS(liver_milo,"~/liver_milo_20201008.RDS")
write_csv(milo_res,"/nfs/team205/ed6/data/Ramachandran2019_liver/liver_results_20201008.csv")
liver_milo <- readRDS("~/liver_milo_20201008.RDS")
milo_res <- read_csv("/nfs/team205/ed6/data/Ramachandran2019_liver/liver_results_20201008.csv")
## Load hvgs
hvgs <- scan("~/liver_milo_hvgs.txt", "")
Making figures for the manuscript
colourCount = length(unique(liver_milo$annotation_lineage))
getPalette = colorRampPalette(brewer.pal(9, "Set2"))
umap_df <- data.frame(reducedDim(liver_milo, "UMAP"))
colnames(umap_df) <- c("UMAP_1", "UMAP_2")
umap1 <- cbind(umap_df, annotation_lineage=liver_milo$annotation_lineage) %>%
ggplot(aes(UMAP_1, UMAP_2, color=as.character(annotation_lineage))) +
geom_point(size=0.1, alpha=0.5) +
ggrepel::geom_text_repel(data = . %>%
group_by(annotation_lineage) %>%
summarise(UMAP_1=mean(UMAP_1), UMAP_2=mean(UMAP_2)),
aes(label=annotation_lineage), color="black", size=6
) +
scale_color_manual(values=getPalette(colourCount)) +
guides(color="none") +
xlab("UMAP1") + ylab("UMAP2") +
coord_fixed() +
theme_classic(base_size = 22) +
theme(axis.text = element_blank(), axis.ticks = element_blank())
umap2 <-
cbind(umap_df, condition=as.character(liver_milo$condition)) %>%
ggplot(aes(UMAP_1, UMAP_2, color=condition)) +
geom_point(size=0.1, alpha=0.5) +
scale_color_brewer(palette="Set1", name='') +
xlab("UMAP1") + ylab("UMAP2") +
coord_fixed() +
guides(color='none') +
facet_wrap(condition~., ncol=1) +
theme_nothing(font_size = 22) +
theme(axis.text = element_blank(), axis.ticks = element_blank(), legend.position=c(0.9,0.9),
strip.background = element_rect(color=NA), strip.text = element_text(size=22))
nh_graph_pl <- plotNhoodGraphDA(liver_milo, milo_res, alpha = 0.1) +
theme(legend.text = element_text(size=22), legend.title = element_text(size=24)) +
coord_fixed()
fig4_top <- (umap1 | umap2 | nh_graph_pl) +
plot_layout(widths = c(3,1,3))
fig4_top +
ggsave("~/milo_output/liver_embedding.pdf", width=15, height = 10)
Next, we can check the cell types where we observe most differences between healthy and cirrhotic cells, by taking the most frequent cell type in each neighbourhood.
# Add annotation of most frequent cell type per nhood to milo results table
milo_res <- annotateNhoods(liver_milo, milo_res, "annotation_indepth")
anno_df <- data.frame(liver_milo@colData) %>%
distinct(annotation_lineage, annotation_indepth)
milo_res <- left_join(milo_res, anno_df, by="annotation_indepth")
We first check that neighbourhoods are quite homogeneous
frac_hist <- ggplot(milo_res, aes(annotation_indepth_fraction)) +
geom_histogram(bins=30) +
xlab("Fraction of cells in \nmost abundant cluster") +
ylab("# neighbourhoods") +
theme_bw(base_size=14)
frac_hist

I can recover all the clusters where DA was detected in the original paper (see all the barplots for each lineage) and more! All in a single analysis, and without knowing where the subclusters are. Let’s bear in mind that positive logFC

Close-up on Endothelial lineage
endo_milo <- scater::runUMAP(liver_milo[,liver_milo$annotation_lineage=="Endothelia"], dimred='PCA')
plotUMAP(endo_milo, colour_by = "annotation_indepth")

umap_df <- data.frame(reducedDim(endo_milo, "UMAP"))
colnames(umap_df) <- c("UMAP_1", "UMAP_2")
endo_umap <- cbind(umap_df, condition=endo_milo$condition) %>%
ggplot(aes(UMAP_1, UMAP_2, color=condition)) +
geom_point(size=0.3, alpha=0.5) +
scale_color_brewer(palette="Set1", name='') +
xlab("UMAP1") + ylab("UMAP2") +
coord_fixed() +
guides(color="none") +
facet_wrap(condition~., ncol=1) +
theme_nothing() +
theme(axis.text = element_blank(), axis.ticks = element_blank(), legend.position=c(0.9,0.9),
strip.background = element_rect(color=NA), strip.text = element_text(size=22))
liver_milo2 <- liver_milo
subset.nhoods <- str_detect(milo_res$annotation_indepth, "Endo")
reducedDim(liver_milo2, "UMAP")[colnames(endo_milo),] <- reducedDim(endo_milo, "UMAP")
endo_gr <-
plotNhoodGraphDA(
liver_milo2, milo_res,
subset.nhoods = subset.nhoods,
# ) =)[1:(length()-1)],
alpha = 0.1
) +
theme(legend.text = element_text(size=22), legend.title = element_text(size=24))
fig4_bright1 <- ((endo_umap + endo_gr ) +
plot_layout(widths = c(1,2),
guides = "collect"
))
fig4_bright1 +
ggsave("~/milo_output/liver_endoGraph.pdf", width=9, height = 5)

Close-up on Cholangiocytes

Filter out cells that show contamination from immune cells (expression of immune markers)
keep <- logcounts(chol_milo)["CD19",] == 0 | logcounts(chol_milo)["MS4A1",] == 0
chol_milo <- chol_milo[,keep]
chol_milo <- scater::runUMAP(chol_milo, dimred='PCA')
plotUMAP(chol_milo, colour_by = "annotation_indepth")
umap_df <- data.frame(reducedDim(chol_milo, "UMAP"))
colnames(umap_df) <- c("UMAP_1", "UMAP_2")
chol_umap <- cbind(umap_df, condition=chol_milo$condition) %>%
ggplot(aes(UMAP_1, UMAP_2, color=condition)) +
geom_point(size=0.3, alpha=0.5) +
scale_color_brewer(palette="Set1", name='') +
xlab("UMAP1") + ylab("UMAP2") +
coord_fixed() +
guides(color="none") +
facet_wrap(condition~., ncol=1) +
theme_nothing() +
theme(axis.text = element_blank(), axis.ticks = element_blank(), legend.position=c(0.9,0.9),
strip.background = element_rect(color=NA), strip.text = element_text(size=22))
chol_umap

liver_milo2 <- liver_milo
subset.nhoods <- str_detect(milo_res$annotation_indepth, "Cholangio")
reducedDim(liver_milo2, "UMAP")[colnames(chol_milo),] <- reducedDim(chol_milo, "UMAP")
chol_gr <-
plotNhoodGraphDA(
liver_milo2, milo_res,
subset.nhoods = subset.nhoods,
# ) =)[1:(length()-1)],
alpha = 0.1
) +
theme(legend.text = element_text(size=22), legend.title = element_text(size=24))
(chol_umap + chol_gr ) +
plot_layout(widths = c(1,2),
guides = "collect"
)

# fig4_bright1 +
# ggsave("~/milo_output/liver_endoGraph.pdf", width=9, height = 5)
DGE analysis
Feature selection
dec_liver <- modelGeneVar(liver_milo)
fit_liver <- metadata(dec_liver)
hvgs <- getTopHVGs(dec_liver, n=3000)
Add nhood expression to speed-up plotting of heatmaps
liver_milo <- calcNhoodExpression(liver_milo, assay = "logcounts", subset.row = hvgs)
Endothelia
unique(nhs.da.gr)
[1] 1 2 3
Visualize as volcano
marker.df %>%
mutate(label=ifelse((adj.P.Val_2) < 0.01, GeneID, NA)) %>%
ggplot(aes(logFC_2, -log10(adj.P.Val_2),
# color=highlight
)) +
geom_point() +
ggrepel::geom_text_repel(aes(label=label)) +
xlab("logFC") + ylab("- log10(Adj. P value)") +
theme_bw(base_size = 22)

marker.df %>%
mutate(label=ifelse((adj.P.Val_1) < 0.01, GeneID, NA)) %>%
ggplot(aes(logFC_1, -log10(adj.P.Val_1),
# color=highlight
)) +
geom_point() +
ggrepel::geom_text_repel(aes(label=label)) +
xlab("logFC") + ylab("- log10(Adj. P value)") +
theme_bw(base_size = 22)

NA
NA
Visualize as heatmap
(gene expression values are scaled between 0 and 1 for each gene)

GO term analysis

em_res_up
em_res_down
Cholangiocytes
x = liver_milo
da.res = milo_res
subset.row = hvgs
assay="counts"
aggregate.samples = TRUE
sample_col = "dataset"
gene.offset=TRUE
subset.nhoods = milo_res$annotation_lineage=="Cholangiocytes"
overlap=1
nhood.adj <- nhoodAdjacency(liver_milo)[as.character(unlist(nhoodIndex(liver_milo)[subset.nhoods])),as.character(unlist(nhoodIndex(liver_milo)[subset.nhoods]))]
nhood.adj[which(milo_res[subset.nhoods, "logFC"] > 0),which(milo_res[subset.nhoods, "logFC"] < 0)] <- 0
nhood.adj[which(milo_res[subset.nhoods, "logFC"] < 0),which(milo_res[subset.nhoods, "logFC"] > 0)] <- 0
nhood.adj[nhood.adj < overlap] <- 0
g <- graph_from_adjacency_matrix(nhood.adj)
nhs.da.gr <- components(g)$membership
nhood.gr <- unique(nhs.da.gr)
# perform DGE _within_ each group of cells using the input design matrix
message(paste0("Nhoods aggregated into ", length(nhood.gr), " groups"))
Nhoods aggregated into 3 groups
fake.meta <- data.frame("CellID"=colnames(x), "Nhood.Group"=rep(NA, ncol(x)))
rownames(fake.meta) <- fake.meta$CellID
# do we want to allow cells to be members of multiple groups? This will create
# chaos for the LM as there will be a dependency structure comparing 2 different
# groups that contain overlapping cells.
# this approach means that the latter group takes precedent.
# maybe exclude the cells that fall into separate groups?
for(i in seq_along(nhood.gr)){
nhood.x <- nhs.da.gr == nhood.gr[i]
# get the nhoods
nhs <- nhoods(x)
if(!is.null(subset.nhoods)){
nhs <- nhs[subset.nhoods]
}
if(!any(is.na(fake.meta[unlist(nhs[nhood.x]),]$Nhood.Group))){
fake.meta[unlist(nhs[nhood.x]),]$Nhood.Group[!is.na(fake.meta[unlist(nhs[nhood.x]),]$Nhood.Group)] <- NA
} else{
fake.meta[unlist(nhs[nhood.x]),]$Nhood.Group <- nhood.gr[i]
}
}
# only compare against the other DA neighbourhoods
x <- x[, !is.na(fake.meta$Nhood.Group)]
fake.meta <- fake.meta[!is.na(fake.meta$Nhood.Group), ]
if(!is.null(subset.row)){
x <- x[subset.row, , drop=FALSE]
}
exprs <- assay(x, assay)
marker.list <- list()
i.contrast <- c("TestTest - TestRef") # always use contrasts for this
# if there is only 1 group, then need to make sure that all neighbourhoods
# are not in this group - otherwise can't do any DGE testing
if(length(nhood.gr) == 1){
if(sum(fake.meta$Nhood.Group == nhood.gr[1]) == nrow(fake.meta)){
warning("All graph neighbourhoods are in the same group - cannot perform DGE testing. Returning NULL")
return(NULL)
}
}
## Aggregate expression by sample
# To avoid treating cells as independent replicates
if (isTRUE(aggregate.samples)) {
fake.meta[,"sample_id"] <- colData(x)[[sample_col]]
fake.meta[,'sample_group'] <- paste(fake.meta[,"sample_id"], fake.meta[,"Nhood.Group"], sep="_")
sample_gr_mat <- matrix(0, nrow=nrow(fake.meta), ncol=length(unique(fake.meta$sample_group)))
colnames(sample_gr_mat) <- unique(fake.meta$sample_group)
rownames(sample_gr_mat) <- rownames(fake.meta)
for (s in colnames(sample_gr_mat)) {
sample_gr_mat[which(fake.meta$sample_group == s),s] <- 1
}
## Summarise expression by sample
exprs_smp <- matrix(0, nrow=nrow(exprs), ncol=ncol(sample_gr_mat))
if (assay=='counts') {
summFunc <- rowSums
} else {
summFunc <- rowMeans
}
for (i in 1:ncol(sample_gr_mat)){
if (sum(sample_gr_mat[,i]) > 1) {
exprs_smp[,i] <- summFunc(exprs[,which(sample_gr_mat[,i] > 0)])
} else {
exprs_smp[,i] <- exprs[,which(sample_gr_mat[,i] > 0)]
}
}
rownames(exprs_smp) <- rownames(exprs)
colnames(exprs_smp) <- colnames(sample_gr_mat)
smp_meta <- distinct(fake.meta, sample_group, Nhood.Group)
rownames(smp_meta) <- smp_meta[,"sample_group"]
fake.meta <- smp_meta
exprs <- exprs_smp
}
for(i in seq_along(nhood.gr)){
i.meta <- fake.meta
i.meta$Test <- "Ref"
i.meta$Test[fake.meta$Nhood.Group == nhood.gr[i]] <- "Test"
if(ncol(exprs) > 1 & nrow(i.meta) > 1){
i.design <- as.formula(" ~ 0 + Test")
i.model <- model.matrix(i.design, data=i.meta)
rownames(i.model) <- rownames(i.meta)
}
sink(file="/dev/null")
gc()
sink(file=NULL)
if(assay == "logcounts"){
i.res <- .perform_lognormal_dge(exprs, i.model, model.contrasts=i.contrast,
gene.offset=gene.offset)
} else if(assay == "counts"){
i.res <- .perform_counts_dge(exprs, i.model, model.contrasts=i.contrast,
gene.offset=gene.offset)
colnames(i.res)[ncol(i.res)] <- "adj.P.Val"
} else{
warning("Assay type is not counts or logcounts - assuming (log)-normal distribution. Use these results at your peril")
i.res <- .perform_lognormal_dge(exprs, i.model,
model.contrasts=i.contrast,
gene.offset=gene.offset)
}
i.res$adj.P.Val[is.na(i.res$adj.P.Val)] <- 1
i.res$logFC[is.infinite(i.res$logFC)] <- 0
i.res <- i.res[, c("logFC", "adj.P.Val")]
colnames(i.res) <- paste(colnames(i.res), nhood.gr[i], sep="_")
marker.list[[paste0(nhood.gr[i])]] <- i.res
}
marker.df.chol <- do.call(cbind.data.frame, marker.list)
colnames(marker.df.chol) <- gsub(colnames(marker.df.chol), pattern="^[0-9]+\\.", replacement="")
marker.df.chol$GeneID <- rownames(i.res)
table(nhs.da.gr)
nhs.da.gr
1 2 3
114 40 1
Visualize as volcano

Visualize as heatmap
(gene expression values are scaled between 0 and 1 for each gene)

GO term analysis

em_res_up_chol
Assemble figure
fig4_bottom <- ((fig4_bleft + plot_layout()) |
((fig4_bright1 + plot_layout(tag_level = 'keep')) / (fig4_bbright + plot_layout())) +
plot_layout(heights = c(1,1.6))
) +
plot_layout(widths=c(1,1.2))
(fig4_top / fig4_bottom) +
plot_layout(heights=c(1,1.8)) +
ggsave("~/milo_output/fig4.pdf", height = 26, width = 22, useDingbats=FALSE)
# ggsave("~/milo/ms/figures/figs/figure5.pdf", height = 26, width = 22, useDingbats=FALSE)
Assemble supplementary figure

LS0tCnRpdGxlOiAiTWlsbzogbGl2ZXIgY2lycmhvc2lzIGFuYWx5c2lzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgojIyBJbnRyb2R1Y3Rpb24KCkluIHRoaXMgbm90ZWJvb2sgd2UgZGVtb25zdHJhdGUgaG93IHRvIHVzZSBNaWxvIHRvIGRldGVjdCBhYmhlcnJhbnQgY2VsbCBzdGF0ZXMgaW4gZGlzZWFzZWQgdGlzc3VlcywgdXNpbmcgYSBkYXRhc2V0IG9mIGhlcGF0aWMgbm9uLXBhcmVuY2h5bWFsIGNlbGxzIGlzb2xhdGVkIGZyb20gNSBoZWFsdGh5IGFuZCA1IGNpcnJob3RpYyBodW1hbiBsaXZlcnMuIFtSYW1hY2hhbmRyYW4gZXQgYWwuIDIwMTldKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTg2LTAxOS0xNjMxLTMjU2VjMSkgKEdFTyBhY2Nlc3NpaW9uOiBHU0UxMzYxMDMpLgoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeSh0aWR5dmVyc2UpCiAgbGlicmFyeShpcmxiYSkKICBsaWJyYXJ5KERyb3BsZXRVdGlscykKICBsaWJyYXJ5KHNjYXRlcikKICBsaWJyYXJ5KHNjcmFuKQogIGxpYnJhcnkoU2V1cmF0KSAjIyBqdXN0IDQgbG9hZGluZyB0aGUgb2JqZWN0CiAgbGlicmFyeShtaWxvUikKICBsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQogIGxpYnJhcnkocGF0Y2h3b3JrKQogIGxpYnJhcnkoaWdyYXBoKQogIGxpYnJhcnkoUkNvbG9yQnJld2VyKQogIGxpYnJhcnkoY293cGxvdCkKICB9KQpgYGAKCiMjIExvYWQgZGF0YQoKV2UgZG93bmxvYWRlZCB0aGUgZGF0YXNldCBhbmQgYW5ub3RhdGlvbnMgc3RvcmVkIGluIFNldXJhdCBvYmplY3QgZnJvbSBbaGVyZV0oaHR0cHM6Ly9kYXRhc2hhcmUuaXMuZWQuYWMudWsvaGFuZGxlLzEwMjgzLzM0MzMpLCBhcyBpbmRpY2F0ZWQgYnkgdGhlIGF1dGhvcnMuCgpgYGB7cn0KbG9hZCgiL25mcy90ZWFtMjA1L2VkNi9kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvdGlzc3VlLnJkYXRhIikKCiMjIENvbnZlcnQgdG8gU2luZ2xlQ2VsbEV4cGVyaW1lbnQKbGl2ZXJfc2NlIDwtIFNpbmdsZUNlbGxFeHBlcmltZW50KGFzc2F5ID0gbGlzdChjb3VudHM9dGlzc3VlQHJhdy5kYXRhLCBsb2djb3VudHM9dGlzc3VlQGRhdGEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IHRpc3N1ZUBtZXRhLmRhdGEpCgpsaXZlcl9zY2UKYGBgCgojIyBQcmVwcm9jZXNzaW5nCgojIyMgRmVhdHVyZSBzZWxlY3Rpb24KCmBgYHtyfQpkZWNfbGl2ZXIgPC0gbW9kZWxHZW5lVmFyKGxpdmVyX3NjZSkKCmZpdF9saXZlciA8LSBtZXRhZGF0YShkZWNfbGl2ZXIpCnBsb3QoZml0X2xpdmVyJG1lYW4sIGZpdF9saXZlciR2YXIsIHhsYWI9Ik1lYW4gb2YgbG9nLWV4cHJlc3Npb24iLAogICAgeWxhYj0iVmFyaWFuY2Ugb2YgbG9nLWV4cHJlc3Npb24iKQoKaHZncyA8LSBnZXRUb3BIVkdzKGRlY19saXZlciwgbj0zMDAwKQpgYGAKCiMjIyBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gd2l0aCBQQ0EKCmBgYHtyLCBmaWcuaGVpZ2h0PTE0LCBmaWcud2lkdGg9MTR9CmxpdmVyX3NjZSA8LSBydW5QQ0EobGl2ZXJfc2NlLCBzdWJzZXRfcm93PWh2Z3MsIG5jb21wb25lbnRzPTExKQoKcGxvdFBDQShsaXZlcl9zY2UsIGNvbG91cl9ieT0iY29uZGl0aW9uIiwgbmNvbXBvbmVudHM9MykKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0KbGl2ZXJfc2NlIDwtIHJ1blVNQVAobGl2ZXJfc2NlLCBkaW1yZWQ9IlBDQSIsIG5jb21wb25lbnRzPTIpCgpzY2F0ZXI6OnBsb3RVTUFQKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJjb25kaXRpb24iLCBwb2ludF9hbHBoYT0xLCAgcG9pbnRfc2l6ZT0wLjUpCnNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9ImRhdGFzZXQiLCBwb2ludF9hbHBoYT0wLjMsICBwb2ludF9zaXplPTAuNSkKc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iYW5ub3RhdGlvbl9saW5lYWdlIiwgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUsIHRleHRfYnk9J2Fubm90YXRpb25fbGluZWFnZScpCiMgc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0nYW5ub3RhdGlvbl9pbmRlcHRoJywgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUsIHRleHRfYnk9J2Fubm90YXRpb25faW5kZXB0aCcpCmBgYAoKTm90YWJseSwgdGhpcyBkYXRhc2V0IGRvZXNuJ3QgYXBwZWFyIHRvIGRpc3BsYXkgYSBiYXRjaCBlZmZlY3QKCiMjIERBIGFuYWx5c2lzIHdpdGggTWlsbwoKV2UgdGVzdCBmb3IgZGlmZmVyZW50aWFsIGFidW5kYW5jZSBiZXR3ZWVuIGhlYWx0aHkgYW5kIGNpcnJob3RpYyBsaXZlcnMuIFdlIHN0YXJ0IGJ5IGRlZmluaW5nIG5laWdoYm91cmhvb2RzIHdpdGggcmVmaW5lZCBzYW1wbGluZyBvbiB0aGUgS05OIGdyYXBoLiBXZSBpbnNwZWN0IHRoZSBzaXplIG9mIG5laWdoYm91cmhvb2RzLgoKYGBge3J9CmxpdmVyX21pbG8gPC0gTWlsbyhsaXZlcl9zY2UpCgojIyBCdWlsZCBLTk4gZ3JhcGgKbGl2ZXJfbWlsbyA8LSBidWlsZEdyYXBoKGxpdmVyX21pbG8sIGQgPSAxMSwgaz0zMCkKCiMjIENvbXB1dGUgbmVpZ2hib3VyaG9vZHMgd2l0aCByZWZpbmVkIHNhbXBsaW5nCmxpdmVyX21pbG8gPC0gbWFrZU5ob29kcyhsaXZlcl9taWxvLCBrPTMwLCBkPTExLCBwcm9wID0gMC4wNSwgcmVmaW5lZD1UUlVFKQpwbG90Tmhvb2RTaXplSGlzdChsaXZlcl9taWxvLCBiaW5zPTE1MCkKYGBgCgpUaGVuIHdlIG1ha2UgYSBkZXNpZ24gbWF0cml4IGZvciB0aGUgZGlmZmVyZW50aWFsIHRlc3QsIGFzc2lnbmluZyBzYW1wbGVzIHRvIGNvbmRpdGlvbnMuCgpgYGB7cn0KbGl2ZXJfbWV0YSA8LSBhcy50aWJibGUoY29sRGF0YShsaXZlcl9taWxvKVssYygiZGF0YXNldCIsImNvbmRpdGlvbiIpXSkKbGl2ZXJfbWV0YSA8LSBkaXN0aW5jdChsaXZlcl9tZXRhKSAlPiUKICBtdXRhdGUoY29uZGl0aW9uPWZhY3Rvcihjb25kaXRpb24sIGxldmVscz1jKCJVbmluanVyZWQiLCAiQ2lycmhvdGljIikpKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImRhdGFzZXQiKQpgYGAKCk5vdyB3ZSBjYW4gY291bnQgY2VsbHMgaW4gbmVpZ2hib3VyaG9vZHMgYW5kIHBlcmZvcm0gdGhlIERBIHRlc3QuCgpgYGB7cn0KbGl2ZXJfbWlsbyA8LSBjb3VudENlbGxzKGxpdmVyX21pbG8sIHNhbXBsZXMgPSAiZGF0YXNldCIsIG1ldGEuZGF0YSA9IGRhdGEuZnJhbWUoY29sRGF0YShsaXZlcl9taWxvKVssYygiZGF0YXNldCIsImNvbmRpdGlvbiIpXSkgKQoKbGl2ZXJfbWlsbyA8LSBjYWxjTmhvb2REaXN0YW5jZShsaXZlcl9taWxvLCBkPTExKQptaWxvX3JlcyA8LSB0ZXN0Tmhvb2RzKGxpdmVyX21pbG8sIGRlc2lnbiA9IH4gY29uZGl0aW9uLCBkZXNpZ24uZGYgPSBsaXZlcl9tZXRhLCBmZHIud2VpZ2h0aW5nID0gImstZGlzdGFuY2UiKQpgYGAKCiMjIEV4cGxvcmF0aW9uIG9mIERBIHJlc3VsdHMKCldlIGNhbiBzdGFydCBieSBsb29raW5nIGF0IHNvbWUgYmFzaWMgc3RhdHMKCmBgYHtyfQpwdmFsX2hpc3QgPC0gbWlsb19yZXMgJT4lCiAgZ2dwbG90KGFlcyhQVmFsdWUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz01MCkgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xNCkKCnZvbGNhbm8gPC0KICBtaWxvX3JlcyAlPiUKICBnZ3Bsb3QoYWVzKGxvZ0ZDLCAtbG9nMTAoU3BhdGlhbEZEUikpKSArCiAgZ2VvbV9wb2ludChzaXplPTAuNCwgYWxwaGE9MC4yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gLWxvZzEwKDAuMSkpICsKICB4bGFiKCJsb2ctRm9sZCBDaGFuZ2UiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE0KQoKcHZhbF9oaXN0ICsgdm9sY2FubwpgYGAKClRoZSBkaXN0cmlidXRpb24gb2YgUC12YWx1ZXMgbG9va3Mgc2Vuc2libGUgYW5kIGZyb20gdGhlIHZvbGNhbm8gcGxvdCB3ZSBjYW4gc2VlIHRoYXQgd2UgaGF2ZSBpZGVudGlmaWVkIHNvbWUgREEgbmVpZ2hib3VyaG9vZHMgYXQgMTAlIEZEUi4KV2UgY2FuIHZpc3VhbGl6ZSBEQSBuZWlnaGJvdXJob29kcyBidWlsZGluZyBhbiBhYnN0cmFjdGVkIGdyYXBoCgpgYGB7ciwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTEwfQpsaXZlcl9taWxvIDwtIGJ1aWxkTmhvb2RHcmFwaChsaXZlcl9taWxvKQpwbG90Tmhvb2RHcmFwaERBKGxpdmVyX21pbG8sIG1pbG9fcmVzLCBhbHBoYSA9IDAuMDUpCmBgYAoKYGBge3J9CiMjIFNhdmUgbWlsbyBvYmplY3QgYW5kIHJlc3VsdHMKc2F2ZVJEUyhsaXZlcl9taWxvLCJ+L2xpdmVyX21pbG9fMjAyMDEwMDguUkRTIikKd3JpdGVfY3N2KG1pbG9fcmVzLCIvbmZzL3RlYW0yMDUvZWQ2L2RhdGEvUmFtYWNoYW5kcmFuMjAxOV9saXZlci9saXZlcl9yZXN1bHRzXzIwMjAxMDA4LmNzdiIpCmBgYAoKYGBge3J9CmxpdmVyX21pbG8gPC0gcmVhZFJEUygifi9saXZlcl9taWxvXzIwMjAxMDA4LlJEUyIpCm1pbG9fcmVzIDwtIHJlYWRfY3N2KCIvbmZzL3RlYW0yMDUvZWQ2L2RhdGEvUmFtYWNoYW5kcmFuMjAxOV9saXZlci9saXZlcl9yZXN1bHRzXzIwMjAxMDA4LmNzdiIpCgojIyBMb2FkIGh2Z3MgCmh2Z3MgPC0gc2Nhbigifi9saXZlcl9taWxvX2h2Z3MudHh0IiwgIiIpCmBgYAoKCgpNYWtpbmcgZmlndXJlcyBmb3IgdGhlIG1hbnVzY3JpcHQKCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTB9CmNvbG91ckNvdW50ID0gbGVuZ3RoKHVuaXF1ZShsaXZlcl9taWxvJGFubm90YXRpb25fbGluZWFnZSkpCmdldFBhbGV0dGUgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOSwgIlNldDIiKSkKCnVtYXBfZGYgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKGxpdmVyX21pbG8sICJVTUFQIikpCmNvbG5hbWVzKHVtYXBfZGYpIDwtIGMoIlVNQVBfMSIsICJVTUFQXzIiKQoKdW1hcDEgPC0gY2JpbmQodW1hcF9kZiwgYW5ub3RhdGlvbl9saW5lYWdlPWxpdmVyX21pbG8kYW5ub3RhdGlvbl9saW5lYWdlKSAlPiUKICBnZ3Bsb3QoYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvcj1hcy5jaGFyYWN0ZXIoYW5ub3RhdGlvbl9saW5lYWdlKSkpICsKICBnZW9tX3BvaW50KHNpemU9MC4xLCBhbHBoYT0wLjUpICsKICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoZGF0YSA9IC4gJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoYW5ub3RhdGlvbl9saW5lYWdlKSAlPiUKICAgICAgICAgICAgICBzdW1tYXJpc2UoVU1BUF8xPW1lYW4oVU1BUF8xKSwgVU1BUF8yPW1lYW4oVU1BUF8yKSksCiAgICAgICAgICAgIGFlcyhsYWJlbD1hbm5vdGF0aW9uX2xpbmVhZ2UpLCBjb2xvcj0iYmxhY2siLCBzaXplPTYKICAgICAgICAgICAgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1nZXRQYWxldHRlKGNvbG91ckNvdW50KSkgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICB4bGFiKCJVTUFQMSIpICsgeWxhYigiVU1BUDIiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAyMikgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSkKCnVtYXAyIDwtCiAgY2JpbmQodW1hcF9kZiwgY29uZGl0aW9uPWFzLmNoYXJhY3RlcihsaXZlcl9taWxvJGNvbmRpdGlvbikpICU+JQogIGdncGxvdChhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG9yPWNvbmRpdGlvbikpICsKICBnZW9tX3BvaW50KHNpemU9MC4xLCBhbHBoYT0wLjUpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIsIG5hbWU9JycpICsKICB4bGFiKCJVTUFQMSIpICsgeWxhYigiVU1BUDIiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ3VpZGVzKGNvbG9yPSdub25lJykgKwogIGZhY2V0X3dyYXAoY29uZGl0aW9ufi4sIG5jb2w9MSkgKwogIHRoZW1lX25vdGhpbmcoZm9udF9zaXplID0gMjIpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj1jKDAuOSwwLjkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9TkEpLCBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjIpKQoKbmhfZ3JhcGhfcGwgPC0gcGxvdE5ob29kR3JhcGhEQShsaXZlcl9taWxvLCBtaWxvX3JlcywgYWxwaGEgPSAwLjEpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjQpKSArCiAgY29vcmRfZml4ZWQoKQoKZmlnNF90b3AgPC0gKHVtYXAxIHwgdW1hcDIgfCBuaF9ncmFwaF9wbCkgKwogIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMywxLDMpKQoKZmlnNF90b3AgKwogIGdnc2F2ZSgifi9taWxvX291dHB1dC9saXZlcl9lbWJlZGRpbmcucGRmIiwgd2lkdGg9MTUsIGhlaWdodCA9IDEwKQpgYGAKCk5leHQsIHdlIGNhbiBjaGVjayB0aGUgY2VsbCB0eXBlcyB3aGVyZSB3ZSBvYnNlcnZlIG1vc3QgZGlmZmVyZW5jZXMgYmV0d2VlbiBoZWFsdGh5IGFuZCBjaXJyaG90aWMgY2VsbHMsIGJ5IHRha2luZyB0aGUgbW9zdCBmcmVxdWVudCBjZWxsIHR5cGUgaW4gZWFjaCBuZWlnaGJvdXJob29kLgoKYGBge3IsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTEwfQojIEFkZCBhbm5vdGF0aW9uIG9mIG1vc3QgZnJlcXVlbnQgY2VsbCB0eXBlIHBlciBuaG9vZCB0byBtaWxvIHJlc3VsdHMgdGFibGUKbWlsb19yZXMgPC0gYW5ub3RhdGVOaG9vZHMobGl2ZXJfbWlsbywgbWlsb19yZXMsICJhbm5vdGF0aW9uX2luZGVwdGgiKQphbm5vX2RmIDwtIGRhdGEuZnJhbWUobGl2ZXJfbWlsb0Bjb2xEYXRhKSAlPiUKICBkaXN0aW5jdChhbm5vdGF0aW9uX2xpbmVhZ2UsIGFubm90YXRpb25faW5kZXB0aCkKbWlsb19yZXMgPC0gbGVmdF9qb2luKG1pbG9fcmVzLCBhbm5vX2RmLCBieT0iYW5ub3RhdGlvbl9pbmRlcHRoIikKYGBgCgpXZSBmaXJzdCBjaGVjayB0aGF0IG5laWdoYm91cmhvb2RzIGFyZSBxdWl0ZSBob21vZ2VuZW91cwoKYGBge3J9CmZyYWNfaGlzdCA8LSBnZ3Bsb3QobWlsb19yZXMsIGFlcyhhbm5vdGF0aW9uX2luZGVwdGhfZnJhY3Rpb24pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0zMCkgKwogIHhsYWIoIkZyYWN0aW9uIG9mIGNlbGxzIGluIFxubW9zdCBhYnVuZGFudCBjbHVzdGVyIikgKwogIHlsYWIoIiMgbmVpZ2hib3VyaG9vZHMiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE0KQoKZnJhY19oaXN0CmBgYAoKSSBjYW4gcmVjb3ZlciBhbGwgdGhlIGNsdXN0ZXJzIHdoZXJlIERBIHdhcyBkZXRlY3RlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXIgKHNlZSBhbGwgdGhlIGJhcnBsb3RzIGZvciBlYWNoIGxpbmVhZ2UpIGFuZCBtb3JlISBBbGwgaW4gYSBzaW5nbGUgYW5hbHlzaXMsIGFuZCB3aXRob3V0IGtub3dpbmcgd2hlcmUgdGhlIHN1YmNsdXN0ZXJzIGFyZS4gTGV0J3MgYmVhciBpbiBtaW5kIHRoYXQgcG9zaXRpdmUgbG9nRkMKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTAsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cmdyb3VwLmJ5ID0gImFubm90YXRpb25faW5kZXB0aCIKcGFwZXJfREEgPC0gbGlzdChjaXJyaG90aWM9YygiTVBzICg0KSIsIk1QcyAoNSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhICg2KSIsICJFbmRvdGhlbGlhICg3KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lcyAoMykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUY2VsbHMgKDIpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXlvZmlicm9ibGFzdHMiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICBoZWFsdGh5PWMoIk1QcyAoNykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYSAoMSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiVGNlbGxzICgxKSIsICJUY2VsbHMgKDMpIiwiVGNlbGxzICgxKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJJTENzICgxKSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICkKCmV4cERBX2RmIDwtIGJpbmRfcm93cygKICBkYXRhLmZyYW1lKGFubm90YXRpb25faW5kZXB0aCA9IHBhcGVyX0RBW1siY2lycmhvdGljIl1dLCBwcmVkX0RBPSJjaXJyaG90aWMiKSwKICBkYXRhLmZyYW1lKGFubm90YXRpb25faW5kZXB0aCA9IHBhcGVyX0RBW1siaGVhbHRoeSJdXSwgcHJlZF9EQT0iaGVhbHRoeSIpCiAgKQoKcGwxIDwtIG1pbG9fcmVzICU+JQogIGxlZnRfam9pbihleHBEQV9kZikgJT4lCiAgbXV0YXRlKGlzX3NpZ25pZiA9IGlmZWxzZShTcGF0aWFsRkRSIDwgMC4xLCAxLCAwKSkgJT4lCiAgbXV0YXRlKGxvZ0ZDX2NvbG9yID0gaWZlbHNlKGlzX3NpZ25pZj09MSwgbG9nRkMsIE5BKSkgJT4lCiAgYXJyYW5nZShhbm5vdGF0aW9uX2xpbmVhZ2UpICU+JQogIG11dGF0ZShOaG9vZD1mYWN0b3IoTmhvb2QsIGxldmVscz11bmlxdWUoTmhvb2QpKSkgJT4lCiAgZ2dwbG90KGFlcyhhbm5vdGF0aW9uX2luZGVwdGgsIGxvZ0ZDLCBjb2xvcj1sb2dGQ19jb2xvcikpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIoKSArCiAgZ3VpZGVzKGNvbG9yPSJub25lIikgKwogIHhsYWIoZ3JvdXAuYnkpICsgeWxhYigiTG9nIEZvbGQgQ2hhbmdlIikgKwogIGdnYmVlc3dhcm06Omdlb21fcXVhc2lyYW5kb20oYWxwaGE9MSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgZmFjZXRfZ3JpZChhbm5vdGF0aW9uX2xpbmVhZ2V+Liwgc2NhbGVzPSJmcmVlIiwgc3BhY2U9ImZyZWUiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTIyKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gIGVsZW1lbnRfdGV4dChhbmdsZT0wKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgKQoKcGwyIDwtIG1pbG9fcmVzICU+JQogIGxlZnRfam9pbihleHBEQV9kZikgJT4lCiAgIyBkcGx5cjo6ZmlsdGVyKCFpcy5uYShwcmVkX0RBKSkgJT4lCiAgZ3JvdXBfYnkoYW5ub3RhdGlvbl9pbmRlcHRoKSAlPiUKICBzdW1tYXJpc2UocHJlZF9EQT1kcGx5cjo6Zmlyc3QocHJlZF9EQSksIGFubm90YXRpb25fbGluZWFnZT1kcGx5cjo6Zmlyc3QoYW5ub3RhdGlvbl9saW5lYWdlKSkgJT4lCiAgbXV0YXRlKGVuZD1pZmVsc2UocHJlZF9EQT09ImhlYWx0aHkiLCAwLCAxKSwKICAgICAgICAgc3RhcnQ9aWZlbHNlKHByZWRfREE9PSJoZWFsdGh5IiwgMSwgMCkpICU+JQogIGdncGxvdChhZXMoYW5ub3RhdGlvbl9pbmRlcHRoLCBzdGFydCwgeGVuZCA9IGFubm90YXRpb25faW5kZXB0aCwgeWVuZCA9IGVuZCwgY29sb3I9cHJlZF9EQSkpICsKICBnZW9tX3NlZ21lbnQoc2l6ZT0xLGFycm93PWFycm93KGxlbmd0aCA9IHVuaXQoMC4xLCAibnBjIiksIHR5cGU9ImNsb3NlZCIpKSArCiAgY29vcmRfZmxpcCgpICsKICB4bGFiKCJhbm5vdGF0aW9uIikgKwogIGZhY2V0X2dyaWQoYW5ub3RhdGlvbl9saW5lYWdlfi4sCiAgICAjIGFubm90YXRpb25fbGluZWFnZX4iUmFtYWNoYW5kcmFuIGV0IGFsLlxuREEgcHJlZGljdGlvbnMiLAogICAgICAgICAgICAgc2NhbGVzPSJmcmVlIiwgc3BhY2U9ImZyZWUiKSArCiAgIyBndWlkZXMoY29sb3I9Im5vbmUiKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiLCBkaXJlY3Rpb24gPSAtMSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoImVucmljaGVkIGluIGNpcnJob3RpYyIsICJlbnJpY2hlZCBpbiBoZWFsdGh5IiksCiAgICAgICAgICAgICAgICAgICAgIG5hLnRyYW5zbGF0ZSA9IEYsCiAgICAgICAgICAgICAgICAgICAgIG5hbWU9IlJhbWFjaGFuZHJhbiBldCBhbC5cbkRBIHByZWRpY3Rpb25zIikgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobmNvbCA9IDEpKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTIyKSArCiAgeWxpbSgtMC4xLDEuMSkgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSxzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTApLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwwLDApLCAiY20iKSwgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpmaWc0X2JsZWZ0IDwtIChwbDIgKyBwbDEgKwogIHBsb3RfbGF5b3V0KHdpZHRocz1jKDEsMTApLCBndWlkZXMgPSAiY29sbGVjdCIpICYgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcsIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gMCkpCgpmaWc0X2JsZWZ0ICsKICBnZ3NhdmUoIn4vbWlsb19vdXRwdXQvbGl2ZXJfREFjb21wYXJpc29uLnBkZiIsIHdpZHRoPTgsIGhlaWdodCA9IDEzKQpgYGAKCiMjIENsb3NlLXVwIG9uIEVuZG90aGVsaWFsIGxpbmVhZ2UKCmBgYHtyfQplbmRvX21pbG8gPC0gc2NhdGVyOjpydW5VTUFQKGxpdmVyX21pbG9bLGxpdmVyX21pbG8kYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSJdLCAgZGltcmVkPSdQQ0EnKQpwbG90VU1BUChlbmRvX21pbG8sIGNvbG91cl9ieSA9ICJhbm5vdGF0aW9uX2luZGVwdGgiKQpgYGAKCjwhLS0gRmlsdGVyIG91dCBjZWxscyB0aGF0IHNob3cgY29udGFtaW5hdGlvbiBmcm9tIGltbXVuZSBjZWxscyAoZXhwcmVzc2lvbiBvZiBpbW11bmUgbWFya2VycykgLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBrZWVwIDwtIGxvZ2NvdW50cyhlbmRvX21pbG8pWyJDRDE5IixdID09IDAgfCBsb2djb3VudHMoZW5kb19taWxvKVsiTVM0QTEiLF0gPT0gMCAtLT4KPCEtLSBrZWVwX2RnZSA8LSBsb2djb3VudHMobGl2ZXJfbWlsbylbIkNEMTkiLF0gPT0gMCB8IGxvZ2NvdW50cyhsaXZlcl9taWxvKVsiTVM0QTEiLF0gPT0gMCAtLT4KPCEtLSBlbmRvX21pbG8gPC0gZW5kb19taWxvWyxrZWVwXSAtLT4KPCEtLSBlbmRvX21pbG8gPC0gc2NhdGVyOjpydW5VTUFQKGVuZG9fbWlsbywgIGRpbXJlZD0nUENBJykgLS0+Cgo8IS0tIHBsb3RVTUFQKGVuZG9fbWlsbywgY29sb3VyX2J5ID0gImFubm90YXRpb25faW5kZXB0aCIpIC0tPgo8IS0tIGBgYCAtLT4KCmBgYHtyfQp1bWFwX2RmIDwtIGRhdGEuZnJhbWUocmVkdWNlZERpbShlbmRvX21pbG8sICJVTUFQIikpCmNvbG5hbWVzKHVtYXBfZGYpIDwtIGMoIlVNQVBfMSIsICJVTUFQXzIiKQoKZW5kb191bWFwIDwtIGNiaW5kKHVtYXBfZGYsIGNvbmRpdGlvbj1lbmRvX21pbG8kY29uZGl0aW9uKSAlPiUKICAgZ2dwbG90KGFlcyhVTUFQXzEsIFVNQVBfMiwgY29sb3I9Y29uZGl0aW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0wLjMsIGFscGhhPTAuNSkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIiwgbmFtZT0nJykgKwogIHhsYWIoIlVNQVAxIikgKyB5bGFiKCJVTUFQMiIpICsKICBjb29yZF9maXhlZCgpICsKICBndWlkZXMoY29sb3I9Im5vbmUiKSArCiAgZmFjZXRfd3JhcChjb25kaXRpb25+LiwgbmNvbD0xKSArCiAgdGhlbWVfbm90aGluZygpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj1jKDAuOSwwLjkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9TkEpLCBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjIpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaXZlcl9taWxvMiA8LSBsaXZlcl9taWxvCnN1YnNldC5uaG9vZHMgPC0gc3RyX2RldGVjdChtaWxvX3JlcyRhbm5vdGF0aW9uX2luZGVwdGgsICJFbmRvIikKcmVkdWNlZERpbShsaXZlcl9taWxvMiwgIlVNQVAiKVtjb2xuYW1lcyhlbmRvX21pbG8pLF0gPC0gcmVkdWNlZERpbShlbmRvX21pbG8sICJVTUFQIikgCgplbmRvX2dyIDwtCiAgcGxvdE5ob29kR3JhcGhEQSgKICBsaXZlcl9taWxvMiwgbWlsb19yZXMsCiAgc3Vic2V0Lm5ob29kcyA9IHN1YnNldC5uaG9vZHMsIAogICMgKSA9KVsxOihsZW5ndGgoKS0xKV0sIAogIGFscGhhID0gMC4xCiAgKSAgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjQpKQogIApmaWc0X2JyaWdodDEgPC0gKChlbmRvX3VtYXAgKyBlbmRvX2dyICkgKyAKICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsMiksIAogICAgICAgICAgICAgICAgZ3VpZGVzID0gImNvbGxlY3QiCiAgICAgICAgICAgICAgICApKSAKZmlnNF9icmlnaHQxICsKICBnZ3NhdmUoIn4vbWlsb19vdXRwdXQvbGl2ZXJfZW5kb0dyYXBoLnBkZiIsIHdpZHRoPTksIGhlaWdodCA9IDUpICAKYGBgCgojIyBDbG9zZS11cCBvbiBDaG9sYW5naW9jeXRlcwoKYGBge3J9CmNob2xfbWlsbyA8LSBzY2F0ZXI6OnJ1blVNQVAobGl2ZXJfbWlsb1ssbGl2ZXJfbWlsbyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJDaG9sYW5naW9jeXRlcyJdLCAgZGltcmVkPSdQQ0EnKQpwbG90VU1BUChjaG9sX21pbG8sIGNvbG91cl9ieSA9ICJhbm5vdGF0aW9uX2luZGVwdGgiKQoKcGxvdFVNQVAoY2hvbF9taWxvLCBjb2xvdXJfYnkgPSAicGVyY2VudC5taXRvIikKYGBgCgpGaWx0ZXIgb3V0IGNlbGxzIHRoYXQgc2hvdyBjb250YW1pbmF0aW9uIGZyb20gaW1tdW5lIGNlbGxzIChleHByZXNzaW9uIG9mIGltbXVuZSBtYXJrZXJzKQoKYGBge3J9CmtlZXAgPC0gbG9nY291bnRzKGNob2xfbWlsbylbIkNEMTkiLF0gPT0gMCB8IGxvZ2NvdW50cyhjaG9sX21pbG8pWyJNUzRBMSIsXSA9PSAwCmNob2xfbWlsbyA8LSBjaG9sX21pbG9bLGtlZXBdCmNob2xfbWlsbyA8LSBzY2F0ZXI6OnJ1blVNQVAoY2hvbF9taWxvLCAgZGltcmVkPSdQQ0EnKQoKcGxvdFVNQVAoY2hvbF9taWxvLCBjb2xvdXJfYnkgPSAiYW5ub3RhdGlvbl9pbmRlcHRoIikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CnVtYXBfZGYgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKGNob2xfbWlsbywgIlVNQVAiKSkKY29sbmFtZXModW1hcF9kZikgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCgpjaG9sX3VtYXAgPC0gY2JpbmQodW1hcF9kZiwgY29uZGl0aW9uPWNob2xfbWlsbyRjb25kaXRpb24pICU+JQogICBnZ3Bsb3QoYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvcj1jb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplPTAuMywgYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiLCBuYW1lPScnKSArCiAgeGxhYigiVU1BUDEiKSArIHlsYWIoIlVNQVAyIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICBmYWNldF93cmFwKGNvbmRpdGlvbn4uLCBuY29sPTEpICsKICB0aGVtZV9ub3RoaW5nKCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPWMoMC45LDAuOSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj1OQSksIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMikpCgpjaG9sX3VtYXAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGl2ZXJfbWlsbzIgPC0gbGl2ZXJfbWlsbwpzdWJzZXQubmhvb2RzIDwtIHN0cl9kZXRlY3QobWlsb19yZXMkYW5ub3RhdGlvbl9pbmRlcHRoLCAiQ2hvbGFuZ2lvIikKcmVkdWNlZERpbShsaXZlcl9taWxvMiwgIlVNQVAiKVtjb2xuYW1lcyhjaG9sX21pbG8pLF0gPC0gcmVkdWNlZERpbShjaG9sX21pbG8sICJVTUFQIikgCgpjaG9sX2dyIDwtCiAgcGxvdE5ob29kR3JhcGhEQSgKICBsaXZlcl9taWxvMiwgbWlsb19yZXMsCiAgc3Vic2V0Lm5ob29kcyA9IHN1YnNldC5uaG9vZHMsIAogICMgKSA9KVsxOihsZW5ndGgoKS0xKV0sIAogIGFscGhhID0gMC4xCiAgKSAgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjQpKQogIAooY2hvbF91bWFwICsgY2hvbF9nciApICsgCiAgcGxvdF9sYXlvdXQod2lkdGhzID0gYygxLDIpLCAKICAgICAgICAgICAgICAgIGd1aWRlcyA9ICJjb2xsZWN0IgogICAgICAgICAgICAgICAgKQojIGZpZzRfYnJpZ2h0MSArCiMgICBnZ3NhdmUoIn4vbWlsb19vdXRwdXQvbGl2ZXJfZW5kb0dyYXBoLnBkZiIsIHdpZHRoPTksIGhlaWdodCA9IDUpICAKCmBgYAoKIyMjIERHRSBhbmFseXNpcwoKCiMjIEZlYXR1cmUgc2VsZWN0aW9uCmBgYHtyfQpkZWNfbGl2ZXIgPC0gbW9kZWxHZW5lVmFyKGxpdmVyX21pbG8pCmZpdF9saXZlciA8LSBtZXRhZGF0YShkZWNfbGl2ZXIpCmh2Z3MgPC0gZ2V0VG9wSFZHcyhkZWNfbGl2ZXIsIG49MzAwMCkKYGBgCgpBZGQgbmhvb2QgZXhwcmVzc2lvbiB0byBzcGVlZC11cCBwbG90dGluZyBvZiBoZWF0bWFwcwpgYGB7cn0KbGl2ZXJfbWlsbyA8LSBjYWxjTmhvb2RFeHByZXNzaW9uKGxpdmVyX21pbG8sIGFzc2F5ID0gImxvZ2NvdW50cyIsIHN1YnNldC5yb3cgPSBodmdzKQpgYGAKCgojIyBFbmRvdGhlbGlhCgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBzdWJzZXQubmhvb2RzID0gbWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIgLS0+CjwhLS0gbmhvb2RBZGphY2VuY3kobGl2ZXJfbWlsbykgPC0gbmhvb2RBZGphY2VuY3kobGl2ZXJfbWlsbylbbmFtZXMobmhvb2RzKGxpdmVyX21pbG8pKSxuYW1lcyhuaG9vZHMobGl2ZXJfbWlsbykpXSAtLT4KPCEtLSBlbmRvX21hcmtlcnMgPC0gZmluZE5ob29kTWFya2VycyhsaXZlcl9taWxvLCBtaWxvX3JlcywgZGEuZmRyID0gMC4xLGFnZ3JlZ2F0ZS5zYW1wbGVzID0gVFJVRSwgc2FtcGxlX2NvbCA9ICJkYXRhc2V0IiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICBvdmVybGFwID0gMSwgbGZjLnRocmVzaG9sZCA9IDAuMSwgbWVyZ2UuZGlzY29yZCA9IEZBTFNFLCAgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAjIHN1YnNldC5uaG9vZHMgPSBtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIiwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gYXMuY2hhcmFjdGVyKHVubGlzdChuaG9vZEluZGV4KGxpdmVyX21pbG8pW3N1YnNldC5uaG9vZHNdKSksIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgc3Vic2V0LnJvdyA9IE5VTEwsIGNvbXB1dGUubmV3ID0gRkFMU0UsIGFzc2F5ID0gImNvdW50cyIpIC0tPgo8IS0tIGBgYCAtLT4KYGBge3J9CnggPSBsaXZlcl9taWxvCmRhLnJlcyA9IG1pbG9fcmVzCnN1YnNldC5yb3cgPSBodmdzCmFzc2F5PSJjb3VudHMiCmFnZ3JlZ2F0ZS5zYW1wbGVzID0gVFJVRQpzYW1wbGVfY29sID0gImRhdGFzZXQiCmdlbmUub2Zmc2V0PVRSVUUKCnN1YnNldC5uaG9vZHMgPSBtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIgpvdmVybGFwPTEKCm5ob29kLmFkaiA8LSBuaG9vZEFkamFjZW5jeShsaXZlcl9taWxvKVthcy5jaGFyYWN0ZXIodW5saXN0KG5ob29kSW5kZXgobGl2ZXJfbWlsbylbc3Vic2V0Lm5ob29kc10pKSxhcy5jaGFyYWN0ZXIodW5saXN0KG5ob29kSW5kZXgobGl2ZXJfbWlsbylbc3Vic2V0Lm5ob29kc10pKV0KCm5ob29kLmFkalt3aGljaChtaWxvX3Jlc1tzdWJzZXQubmhvb2RzLCAibG9nRkMiXSA+IDApLHdoaWNoKG1pbG9fcmVzW3N1YnNldC5uaG9vZHMsICJsb2dGQyJdIDwgMCldIDwtIDAKbmhvb2QuYWRqW3doaWNoKG1pbG9fcmVzW3N1YnNldC5uaG9vZHMsICJsb2dGQyJdIDwgMCksd2hpY2gobWlsb19yZXNbc3Vic2V0Lm5ob29kcywgImxvZ0ZDIl0gPiAwKV0gPC0gMAoKbmhvb2QuYWRqW25ob29kLmFkaiA8IG92ZXJsYXBdIDwtIDAgCmcgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KG5ob29kLmFkaikKbmhzLmRhLmdyIDwtIGNvbXBvbmVudHMoZykkbWVtYmVyc2hpcAoKCm5ob29kLmdyIDwtIHVuaXF1ZShuaHMuZGEuZ3IpCiMgcGVyZm9ybSBER0UgX3dpdGhpbl8gZWFjaCBncm91cCBvZiBjZWxscyB1c2luZyB0aGUgaW5wdXQgZGVzaWduIG1hdHJpeAptZXNzYWdlKHBhc3RlMCgiTmhvb2RzIGFnZ3JlZ2F0ZWQgaW50byAiLCBsZW5ndGgobmhvb2QuZ3IpLCAiIGdyb3VwcyIpKQoKZmFrZS5tZXRhIDwtIGRhdGEuZnJhbWUoIkNlbGxJRCI9Y29sbmFtZXMoeCksICJOaG9vZC5Hcm91cCI9cmVwKE5BLCBuY29sKHgpKSkKcm93bmFtZXMoZmFrZS5tZXRhKSA8LSBmYWtlLm1ldGEkQ2VsbElECgojIGRvIHdlIHdhbnQgdG8gYWxsb3cgY2VsbHMgdG8gYmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHM/IFRoaXMgd2lsbCBjcmVhdGUKIyBjaGFvcyBmb3IgdGhlIExNIGFzIHRoZXJlIHdpbGwgYmUgYSBkZXBlbmRlbmN5IHN0cnVjdHVyZSBjb21wYXJpbmcgMiBkaWZmZXJlbnQKIyBncm91cHMgdGhhdCBjb250YWluIG92ZXJsYXBwaW5nIGNlbGxzLgojIHRoaXMgYXBwcm9hY2ggbWVhbnMgdGhhdCB0aGUgbGF0dGVyIGdyb3VwIHRha2VzIHByZWNlZGVudC4KIyBtYXliZSBleGNsdWRlIHRoZSBjZWxscyB0aGF0IGZhbGwgaW50byBzZXBhcmF0ZSBncm91cHM/CmZvcihpIGluIHNlcV9hbG9uZyhuaG9vZC5ncikpewogICAgbmhvb2QueCA8LSBuaHMuZGEuZ3IgPT0gbmhvb2QuZ3JbaV0KICAgICMgZ2V0IHRoZSBuaG9vZHMKICAgIG5ocyA8LSBuaG9vZHMoeCkKICAgIGlmKCFpcy5udWxsKHN1YnNldC5uaG9vZHMpKXsKICAgICAgICBuaHMgPC0gbmhzW3N1YnNldC5uaG9vZHNdCiAgICB9CgogICAgaWYoIWFueShpcy5uYShmYWtlLm1ldGFbdW5saXN0KG5oc1tuaG9vZC54XSksXSROaG9vZC5Hcm91cCkpKXsKICAgICAgICBmYWtlLm1ldGFbdW5saXN0KG5oc1tuaG9vZC54XSksXSROaG9vZC5Hcm91cFshaXMubmEoZmFrZS5tZXRhW3VubGlzdChuaHNbbmhvb2QueF0pLF0kTmhvb2QuR3JvdXApXSA8LSBOQQogICAgICAgIH0gZWxzZXsKICAgICAgICAgICAgZmFrZS5tZXRhW3VubGlzdChuaHNbbmhvb2QueF0pLF0kTmhvb2QuR3JvdXAgPC0gbmhvb2QuZ3JbaV0KICAgICAgICB9Cn0KCiMgb25seSBjb21wYXJlIGFnYWluc3QgdGhlIG90aGVyIERBIG5laWdoYm91cmhvb2RzCnggPC0geFssICFpcy5uYShmYWtlLm1ldGEkTmhvb2QuR3JvdXApXQpmYWtlLm1ldGEgPC0gZmFrZS5tZXRhWyFpcy5uYShmYWtlLm1ldGEkTmhvb2QuR3JvdXApLCBdCgppZighaXMubnVsbChzdWJzZXQucm93KSl7CiAgICB4IDwtIHhbc3Vic2V0LnJvdywgLCBkcm9wPUZBTFNFXQp9CgpleHBycyA8LSBhc3NheSh4LCBhc3NheSkKCm1hcmtlci5saXN0IDwtIGxpc3QoKQppLmNvbnRyYXN0IDwtIGMoIlRlc3RUZXN0IC0gVGVzdFJlZiIpICMgYWx3YXlzIHVzZSBjb250cmFzdHMgZm9yIHRoaXMKCiAgICAjIGlmIHRoZXJlIGlzIG9ubHkgMSBncm91cCwgdGhlbiBuZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGFsbCBuZWlnaGJvdXJob29kcwogICAgIyBhcmUgbm90IGluIHRoaXMgZ3JvdXAgLSBvdGhlcndpc2UgY2FuJ3QgZG8gYW55IERHRSB0ZXN0aW5nCiAgICBpZihsZW5ndGgobmhvb2QuZ3IpID09IDEpewogICAgICAgIGlmKHN1bShmYWtlLm1ldGEkTmhvb2QuR3JvdXAgPT0gbmhvb2QuZ3JbMV0pID09IG5yb3coZmFrZS5tZXRhKSl7CiAgICAgICAgICAgIHdhcm5pbmcoIkFsbCBncmFwaCBuZWlnaGJvdXJob29kcyBhcmUgaW4gdGhlIHNhbWUgZ3JvdXAgLSBjYW5ub3QgcGVyZm9ybSBER0UgdGVzdGluZy4gUmV0dXJuaW5nIE5VTEwiKQogICAgICAgICAgICByZXR1cm4oTlVMTCkKICAgICAgICB9CiAgICB9CiAgICAKICAgICMjIEFnZ3JlZ2F0ZSBleHByZXNzaW9uIGJ5IHNhbXBsZQogICAgIyBUbyBhdm9pZCB0cmVhdGluZyBjZWxscyBhcyBpbmRlcGVuZGVudCByZXBsaWNhdGVzCiAgICBpZiAoaXNUUlVFKGFnZ3JlZ2F0ZS5zYW1wbGVzKSkgewogICAgICAgIGZha2UubWV0YVssInNhbXBsZV9pZCJdIDwtIGNvbERhdGEoeClbW3NhbXBsZV9jb2xdXQogICAgICAgIGZha2UubWV0YVssJ3NhbXBsZV9ncm91cCddIDwtIHBhc3RlKGZha2UubWV0YVssInNhbXBsZV9pZCJdLCBmYWtlLm1ldGFbLCJOaG9vZC5Hcm91cCJdLCBzZXA9Il8iKQogICAgICAgIAogICAgICAgIHNhbXBsZV9ncl9tYXQgPC0gbWF0cml4KDAsIG5yb3c9bnJvdyhmYWtlLm1ldGEpLCBuY29sPWxlbmd0aCh1bmlxdWUoZmFrZS5tZXRhJHNhbXBsZV9ncm91cCkpKQogICAgICAgIGNvbG5hbWVzKHNhbXBsZV9ncl9tYXQpIDwtIHVuaXF1ZShmYWtlLm1ldGEkc2FtcGxlX2dyb3VwKQogICAgICAgIHJvd25hbWVzKHNhbXBsZV9ncl9tYXQpIDwtIHJvd25hbWVzKGZha2UubWV0YSkKICAgICAgICAKICAgICAgICBmb3IgKHMgaW4gY29sbmFtZXMoc2FtcGxlX2dyX21hdCkpIHsKICAgICAgICAgICAgc2FtcGxlX2dyX21hdFt3aGljaChmYWtlLm1ldGEkc2FtcGxlX2dyb3VwID09IHMpLHNdIDwtIDEgIAogICAgICAgIH0KICAgICAgICAKICAgICAgICAjIyBTdW1tYXJpc2UgZXhwcmVzc2lvbiBieSBzYW1wbGUKICAgICAgICBleHByc19zbXAgPC0gbWF0cml4KDAsIG5yb3c9bnJvdyhleHBycyksIG5jb2w9bmNvbChzYW1wbGVfZ3JfbWF0KSkKICAgICAgICBpZiAoYXNzYXk9PSdjb3VudHMnKSB7CiAgICAgICAgICAgIHN1bW1GdW5jIDwtIHJvd1N1bXMKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBzdW1tRnVuYyA8LSByb3dNZWFucwogICAgICAgIH0KICAgICAgICAKICAgICAgICBmb3IgKGkgaW4gMTpuY29sKHNhbXBsZV9ncl9tYXQpKXsKICAgICAgICAgICAgaWYgKHN1bShzYW1wbGVfZ3JfbWF0WyxpXSkgPiAxKSB7CiAgICAgICAgICAgICAgICBleHByc19zbXBbLGldIDwtIHN1bW1GdW5jKGV4cHJzWyx3aGljaChzYW1wbGVfZ3JfbWF0WyxpXSA+IDApXSkgIAogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgZXhwcnNfc21wWyxpXSA8LSBleHByc1ssd2hpY2goc2FtcGxlX2dyX21hdFssaV0gPiAwKV0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByb3duYW1lcyhleHByc19zbXApIDwtIHJvd25hbWVzKGV4cHJzKQogICAgICAgIGNvbG5hbWVzKGV4cHJzX3NtcCkgPC0gY29sbmFtZXMoc2FtcGxlX2dyX21hdCkKICAgICAgICAKICAgICAgICBzbXBfbWV0YSA8LSBkaXN0aW5jdChmYWtlLm1ldGEsIHNhbXBsZV9ncm91cCwgTmhvb2QuR3JvdXApCiAgICAgICAgcm93bmFtZXMoc21wX21ldGEpIDwtIHNtcF9tZXRhWywic2FtcGxlX2dyb3VwIl0KICAgICAgICAKICAgICAgICBmYWtlLm1ldGEgPC0gc21wX21ldGEKICAgICAgICBleHBycyA8LSBleHByc19zbXAKICAgIH0KICAgIAogICAgZm9yKGkgaW4gc2VxX2Fsb25nKG5ob29kLmdyKSl7CiAgICAgICAgaS5tZXRhIDwtIGZha2UubWV0YQogICAgICAgIGkubWV0YSRUZXN0IDwtICJSZWYiCiAgICAgICAgaS5tZXRhJFRlc3RbZmFrZS5tZXRhJE5ob29kLkdyb3VwID09IG5ob29kLmdyW2ldXSA8LSAiVGVzdCIKCiAgICAgICAgaWYobmNvbChleHBycykgPiAxICYgbnJvdyhpLm1ldGEpID4gMSl7CiAgICAgICAgICAgIGkuZGVzaWduIDwtIGFzLmZvcm11bGEoIiB+IDAgKyBUZXN0IikKICAgICAgICAgICAgaS5tb2RlbCA8LSBtb2RlbC5tYXRyaXgoaS5kZXNpZ24sIGRhdGE9aS5tZXRhKQogICAgICAgICAgICByb3duYW1lcyhpLm1vZGVsKSA8LSByb3duYW1lcyhpLm1ldGEpCiAgICAgICAgfQoKICAgICAgICBzaW5rKGZpbGU9Ii9kZXYvbnVsbCIpCiAgICAgICAgZ2MoKQogICAgICAgIHNpbmsoZmlsZT1OVUxMKQoKICAgICAgICBpZihhc3NheSA9PSAibG9nY291bnRzIil7CiAgICAgICAgICAgIGkucmVzIDwtIC5wZXJmb3JtX2xvZ25vcm1hbF9kZ2UoZXhwcnMsIGkubW9kZWwsIG1vZGVsLmNvbnRyYXN0cz1pLmNvbnRyYXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUub2Zmc2V0PWdlbmUub2Zmc2V0KQogICAgICAgIH0gZWxzZSBpZihhc3NheSA9PSAiY291bnRzIil7CiAgICAgICAgICAgIGkucmVzIDwtIC5wZXJmb3JtX2NvdW50c19kZ2UoZXhwcnMsIGkubW9kZWwsIG1vZGVsLmNvbnRyYXN0cz1pLmNvbnRyYXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmUub2Zmc2V0PWdlbmUub2Zmc2V0KQogICAgICAgICAgICBjb2xuYW1lcyhpLnJlcylbbmNvbChpLnJlcyldIDwtICJhZGouUC5WYWwiCiAgICAgICAgfSBlbHNlewogICAgICAgICAgICB3YXJuaW5nKCJBc3NheSB0eXBlIGlzIG5vdCBjb3VudHMgb3IgbG9nY291bnRzIC0gYXNzdW1pbmcgKGxvZyktbm9ybWFsIGRpc3RyaWJ1dGlvbi4gVXNlIHRoZXNlIHJlc3VsdHMgYXQgeW91ciBwZXJpbCIpCiAgICAgICAgICAgIGkucmVzIDwtIC5wZXJmb3JtX2xvZ25vcm1hbF9kZ2UoZXhwcnMsIGkubW9kZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwuY29udHJhc3RzPWkuY29udHJhc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZS5vZmZzZXQ9Z2VuZS5vZmZzZXQpCiAgICAgICAgfQoKICAgICAgICBpLnJlcyRhZGouUC5WYWxbaXMubmEoaS5yZXMkYWRqLlAuVmFsKV0gPC0gMQogICAgICAgIGkucmVzJGxvZ0ZDW2lzLmluZmluaXRlKGkucmVzJGxvZ0ZDKV0gPC0gMAoKICAgICAgICBpLnJlcyA8LSBpLnJlc1ssIGMoImxvZ0ZDIiwgImFkai5QLlZhbCIpXQogICAgICAgIGNvbG5hbWVzKGkucmVzKSA8LSBwYXN0ZShjb2xuYW1lcyhpLnJlcyksIG5ob29kLmdyW2ldLCBzZXA9Il8iKQogICAgICAgIG1hcmtlci5saXN0W1twYXN0ZTAobmhvb2QuZ3JbaV0pXV0gPC0gaS5yZXMKICAgIH0KCiAgICBtYXJrZXIuZGYgPC0gZG8uY2FsbChjYmluZC5kYXRhLmZyYW1lLCBtYXJrZXIubGlzdCkKICAgIGNvbG5hbWVzKG1hcmtlci5kZikgPC0gZ3N1Yihjb2xuYW1lcyhtYXJrZXIuZGYpLCBwYXR0ZXJuPSJeWzAtOV0rXFwuIiwgcmVwbGFjZW1lbnQ9IiIpCiAgICBtYXJrZXIuZGYkR2VuZUlEIDwtIHJvd25hbWVzKGkucmVzKQpgYGAKCmBgYHtyfQptYXJrZXIuZGZbbWFya2VyLmRmJGFkai5QLlZhbF8yIDwgMC4xLF0KYGBgCgojIyMjIFZpc3VhbGl6ZSBhcyB2b2xjYW5vIAoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptYXJrZXIuZGYgJT4lCiAgbXV0YXRlKGxhYmVsPWlmZWxzZSgoYWRqLlAuVmFsXzIpIDwgMC4wMSwgR2VuZUlELCBOQSkpICU+JQogIGdncGxvdChhZXMobG9nRkNfMiwgLWxvZzEwKGFkai5QLlZhbF8yKSwgCiAgICAgICAgICAgICAjIGNvbG9yPWhpZ2hsaWdodAogICAgICAgICAgICAgKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdncmVwZWw6Omdlb21fdGV4dF9yZXBlbChhZXMobGFiZWw9bGFiZWwpKSArCiAgeGxhYigibG9nRkMiKSArIHlsYWIoIi0gbG9nMTAoQWRqLiBQIHZhbHVlKSIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAyMikKCm1hcmtlci5kZiAlPiUKICBtdXRhdGUobGFiZWw9aWZlbHNlKChhZGouUC5WYWxfMSkgPCAwLjAxLCBHZW5lSUQsIE5BKSkgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQ18xLCAtbG9nMTAoYWRqLlAuVmFsXzEpLCAKICAgICAgICAgICAgICMgY29sb3I9aGlnaGxpZ2h0CiAgICAgICAgICAgICApKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbD1sYWJlbCkpICsKICB4bGFiKCJsb2dGQyIpICsgeWxhYigiLSBsb2cxMChBZGouIFAgdmFsdWUpIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIyKQoKICAKYGBgCgojIyMjIFZpc3VhbGl6ZSBhcyBoZWF0bWFwIAooZ2VuZSBleHByZXNzaW9uIHZhbHVlcyBhcmUgc2NhbGVkIGJldHdlZW4gMCBhbmQgMSBmb3IgZWFjaCBnZW5lKQoKYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTEyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptYXJrZXJfZ2VuZXMgPC0gbWFya2VyLmRmICU+JQogIGRwbHlyOjpmaWx0ZXIoYWRqLlAuVmFsXzIgPCAwLjEpICU+JQogIHB1bGwoR2VuZUlEKQoKaGlnaGxpZ2h0X2dlbmVzIDwtIGMoIlBMVkFQIiwgIlZXQTEiLCAiQUNLUjEiLCAiSUwzMiIsCiAgICAgICAgICAgICAgICAgICAgICJDTEVDNEciLCAiQ0xFQzRNIiwgIkZDTjIiLCAiRkNOMyIsCiAgICAgICAgICAgICAgICAgICAgICJMRUYxIikKCmZpZzRfYmJyaWdodCA8LSBwbG90Tmhvb2RFeHByZXNzaW9uREEobGl2ZXJfbWlsbywgbWlsb19yZXMsIG1hcmtlcl9nZW5lcywgY2x1c3Rlcl9mZWF0dXJlcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEsCiAgICAgICAgICAgICAgICAgICAgICBzY2FsZV90b18xID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5uaG9vZHMgPSBtaWxvX3JlcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIiwKICAgICAgICAgICAgICAgICAgICAgIGhpZ2hsaWdodF9mZWF0dXJlcyA9IGhpZ2hsaWdodF9nZW5lcywgc2hvd19yb3duYW1lcyA9IEZBTFNFCiAgICAgICAgICAgICAgICAgICAgICApICsKICB5bGFiKCJERSBnZW5lcyIpICsKICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMiksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTI0KSkgKwogIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMTApKSAmIHRoZW1lKGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsNjApLCBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCmZpZzRfYmJyaWdodApgYGAKCiMjIyBHTyB0ZXJtIGFuYWx5c2lzCgpgYGB7ciwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgnY2x1c3RlclByb2ZpbGVyJykKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgnbXNpZ2RicicpCmxpYnJhcnkoY2x1c3RlclByb2ZpbGVyKQpsaWJyYXJ5KG1zaWdkYnIpCgptX2RmIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiKQptX3QyZyA8LSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzUiLCBzdWJjYXRlZ29yeSA9ICJCUCIpICAlPiUgCiAgZHBseXI6OnNlbGVjdChnc19uYW1lLCBnZW5lX3N5bWJvbCkKCm1hcmtlcl9nZW5lc191cCA8LSBtYXJrZXIuZGYgJT4lCiAgZHBseXI6OmZpbHRlcihhZGouUC5WYWxfMiA8IDAuMSAmIGxvZ0ZDXzEgPCAwKSAlPiUKICBwdWxsKEdlbmVJRCkKCm1hcmtlcl9nZW5lc19kb3duIDwtIG1hcmtlci5kZiAlPiUKICBkcGx5cjo6ZmlsdGVyKGFkai5QLlZhbF8xIDwgMC4xICYgbG9nRkNfMSA8IDApICU+JQogIHB1bGwoR2VuZUlEKQoKZW1fdXAgPC0gZW5yaWNoZXIobWFya2VyX2dlbmVzX3VwLCBURVJNMkdFTkU9bV90MmcsIHBBZGp1c3RNZXRob2QgPSAiZmRyIiwgCiAgICAgICAgICAgICAgICAgIHVuaXZlcnNlID0gcm93bmFtZXMobGl2ZXJfbWlsbykKICAgICAgICAgICAgICAgICAgKQplbV9kb3duIDwtIGVucmljaGVyKG1hcmtlcl9nZW5lc19kb3duLCBURVJNMkdFTkU9bV90MmcsIHBBZGp1c3RNZXRob2QgPSAiZmRyIiwgCiAgICAgICAgICAgICAgICAgICAgdW5pdmVyc2UgPSByb3duYW1lcyhsaXZlcl9taWxvKQogICAgICAgICAgICAgICAgICAgICkKCmVtX3Jlc191cCA8LSBlbV91cEByZXN1bHRbZW1fdXBAcmVzdWx0JHF2YWx1ZSA8IDAuMSxdICU+JQogIGRwbHlyOjpzZWxlY3QoLSBjKERlc2NyaXB0aW9uKSkKZW1fcmVzX2Rvd24gPC0gZW1fZG93bkByZXN1bHRbZW1fZG93bkByZXN1bHQkcXZhbHVlIDwgMC4xLF0gJT4lCiAgZHBseXI6OnNlbGVjdCgtIGMoRGVzY3JpcHRpb24pKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ29fZW5kb191cCA8LSBlbV9yZXNfdXAgJT4lCiAgdG9wX24oMjAsIC1sb2cxMChxdmFsdWUpKSAlPiUKICBtdXRhdGUoVGVybT1mYWN0b3IoSUQsIGxldmVscz1yZXYodW5pcXVlKElEKSkpKSAlPiUKICBnZ3Bsb3QoYWVzKFRlcm0sIC1sb2cxMChxdmFsdWUpKSkgKwogIGdlb21fcG9pbnQoKSArCiAgY29vcmRfZmxpcCgpICsKICB4bGFiKCJHTyBCaW9sb2dpY2FsIEZ1bmN0aW9uIikgKyB5bGFiKCItbG9nMTAoQWRqLiBwLXZhbHVlKSIpICsKICB0aGVtZV9idyhiYXNlX3NpemU9MTgpICsKICBnZ3RpdGxlKCJDaXJyaG90aWMgZW5kb3RoZWxpYSIpCgpnb19lbmRvX2Rvd24gPC0gZW1fcmVzX2Rvd24gJT4lCiAgdG9wX24oMjAsIC1sb2cxMChxdmFsdWUpKSAlPiUKICBtdXRhdGUoSUQ9aWZlbHNlKElEPT0nR09fQU5USUdFTl9QUk9DRVNTSU5HX0FORF9QUkVTRU5UQVRJT05fT0ZfUEVQVElERV9PUl9QT0xZU0FDQ0hBUklERV9BTlRJR0VOX1ZJQV9NSENfQ0xBU1NfSUknLCAiR09fQU5USUdFTl9QUkVTRU5UQVRJT05fVklBX01IQ19DTEFTU19JSSIsIElEKSkgJT4lCiAgbXV0YXRlKFRlcm09ZmFjdG9yKElELCBsZXZlbHM9cmV2KHVuaXF1ZShJRCkpKSkgJT4lCiAgZ2dwbG90KGFlcyhUZXJtLCAtbG9nMTAocXZhbHVlKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiR08gQmlvbG9naWNhbCBGdW5jdGlvbiIpICsgeWxhYigiLWxvZzEwKEFkai4gcC12YWx1ZSkiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE4KSArCiAgZ2d0aXRsZSgiVW5pbmp1cmVkIGVuZG90aGVsaWEiKQoKZ29fZW5kb191cApnb19lbmRvX2Rvd24KYGBgCgoKYGBge3J9CmVtX3Jlc191cAplbV9yZXNfZG93bgpgYGAKCiMjIyBDaG9sYW5naW9jeXRlcwpgYGB7cn0KeCA9IGxpdmVyX21pbG8KZGEucmVzID0gbWlsb19yZXMKc3Vic2V0LnJvdyA9IGh2Z3MKYXNzYXk9ImNvdW50cyIKYWdncmVnYXRlLnNhbXBsZXMgPSBUUlVFCnNhbXBsZV9jb2wgPSAiZGF0YXNldCIKZ2VuZS5vZmZzZXQ9VFJVRQoKc3Vic2V0Lm5ob29kcyA9IG1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZT09IkNob2xhbmdpb2N5dGVzIgpvdmVybGFwPTEKCm5ob29kLmFkaiA8LSBuaG9vZEFkamFjZW5jeShsaXZlcl9taWxvKVthcy5jaGFyYWN0ZXIodW5saXN0KG5ob29kSW5kZXgobGl2ZXJfbWlsbylbc3Vic2V0Lm5ob29kc10pKSxhcy5jaGFyYWN0ZXIodW5saXN0KG5ob29kSW5kZXgobGl2ZXJfbWlsbylbc3Vic2V0Lm5ob29kc10pKV0KCm5ob29kLmFkalt3aGljaChtaWxvX3Jlc1tzdWJzZXQubmhvb2RzLCAibG9nRkMiXSA+IDApLHdoaWNoKG1pbG9fcmVzW3N1YnNldC5uaG9vZHMsICJsb2dGQyJdIDwgMCldIDwtIDAKbmhvb2QuYWRqW3doaWNoKG1pbG9fcmVzW3N1YnNldC5uaG9vZHMsICJsb2dGQyJdIDwgMCksd2hpY2gobWlsb19yZXNbc3Vic2V0Lm5ob29kcywgImxvZ0ZDIl0gPiAwKV0gPC0gMAoKbmhvb2QuYWRqW25ob29kLmFkaiA8IG92ZXJsYXBdIDwtIDAgCmcgPC0gZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KG5ob29kLmFkaikKbmhzLmRhLmdyIDwtIGNvbXBvbmVudHMoZykkbWVtYmVyc2hpcAoKCm5ob29kLmdyIDwtIHVuaXF1ZShuaHMuZGEuZ3IpCiMgcGVyZm9ybSBER0UgX3dpdGhpbl8gZWFjaCBncm91cCBvZiBjZWxscyB1c2luZyB0aGUgaW5wdXQgZGVzaWduIG1hdHJpeAptZXNzYWdlKHBhc3RlMCgiTmhvb2RzIGFnZ3JlZ2F0ZWQgaW50byAiLCBsZW5ndGgobmhvb2QuZ3IpLCAiIGdyb3VwcyIpKQoKZmFrZS5tZXRhIDwtIGRhdGEuZnJhbWUoIkNlbGxJRCI9Y29sbmFtZXMoeCksICJOaG9vZC5Hcm91cCI9cmVwKE5BLCBuY29sKHgpKSkKcm93bmFtZXMoZmFrZS5tZXRhKSA8LSBmYWtlLm1ldGEkQ2VsbElECgojIGRvIHdlIHdhbnQgdG8gYWxsb3cgY2VsbHMgdG8gYmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHM/IFRoaXMgd2lsbCBjcmVhdGUKIyBjaGFvcyBmb3IgdGhlIExNIGFzIHRoZXJlIHdpbGwgYmUgYSBkZXBlbmRlbmN5IHN0cnVjdHVyZSBjb21wYXJpbmcgMiBkaWZmZXJlbnQKIyBncm91cHMgdGhhdCBjb250YWluIG92ZXJsYXBwaW5nIGNlbGxzLgojIHRoaXMgYXBwcm9hY2ggbWVhbnMgdGhhdCB0aGUgbGF0dGVyIGdyb3VwIHRha2VzIHByZWNlZGVudC4KIyBtYXliZSBleGNsdWRlIHRoZSBjZWxscyB0aGF0IGZhbGwgaW50byBzZXBhcmF0ZSBncm91cHM/CmZvcihpIGluIHNlcV9hbG9uZyhuaG9vZC5ncikpewogICAgbmhvb2QueCA8LSBuaHMuZGEuZ3IgPT0gbmhvb2QuZ3JbaV0KICAgICMgZ2V0IHRoZSBuaG9vZHMKICAgIG5ocyA8LSBuaG9vZHMoeCkKICAgIGlmKCFpcy5udWxsKHN1YnNldC5uaG9vZHMpKXsKICAgICAgICBuaHMgPC0gbmhzW3N1YnNldC5uaG9vZHNdCiAgICB9CgogICAgaWYoIWFueShpcy5uYShmYWtlLm1ldGFbdW5saXN0KG5oc1tuaG9vZC54XSksXSROaG9vZC5Hcm91cCkpKXsKICAgICAgICBmYWtlLm1ldGFbdW5saXN0KG5oc1tuaG9vZC54XSksXSROaG9vZC5Hcm91cFshaXMubmEoZmFrZS5tZXRhW3VubGlzdChuaHNbbmhvb2QueF0pLF0kTmhvb2QuR3JvdXApXSA8LSBOQQogICAgICAgIH0gZWxzZXsKICAgICAgICAgICAgZmFrZS5tZXRhW3VubGlzdChuaHNbbmhvb2QueF0pLF0kTmhvb2QuR3JvdXAgPC0gbmhvb2QuZ3JbaV0KICAgICAgICB9Cn0KCiMgb25seSBjb21wYXJlIGFnYWluc3QgdGhlIG90aGVyIERBIG5laWdoYm91cmhvb2RzCnggPC0geFssICFpcy5uYShmYWtlLm1ldGEkTmhvb2QuR3JvdXApXQpmYWtlLm1ldGEgPC0gZmFrZS5tZXRhWyFpcy5uYShmYWtlLm1ldGEkTmhvb2QuR3JvdXApLCBdCgppZighaXMubnVsbChzdWJzZXQucm93KSl7CiAgICB4IDwtIHhbc3Vic2V0LnJvdywgLCBkcm9wPUZBTFNFXQp9CgpleHBycyA8LSBhc3NheSh4LCBhc3NheSkKCm1hcmtlci5saXN0IDwtIGxpc3QoKQppLmNvbnRyYXN0IDwtIGMoIlRlc3RUZXN0IC0gVGVzdFJlZiIpICMgYWx3YXlzIHVzZSBjb250cmFzdHMgZm9yIHRoaXMKCiAgICAjIGlmIHRoZXJlIGlzIG9ubHkgMSBncm91cCwgdGhlbiBuZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGFsbCBuZWlnaGJvdXJob29kcwogICAgIyBhcmUgbm90IGluIHRoaXMgZ3JvdXAgLSBvdGhlcndpc2UgY2FuJ3QgZG8gYW55IERHRSB0ZXN0aW5nCiAgICBpZihsZW5ndGgobmhvb2QuZ3IpID09IDEpewogICAgICAgIGlmKHN1bShmYWtlLm1ldGEkTmhvb2QuR3JvdXAgPT0gbmhvb2QuZ3JbMV0pID09IG5yb3coZmFrZS5tZXRhKSl7CiAgICAgICAgICAgIHdhcm5pbmcoIkFsbCBncmFwaCBuZWlnaGJvdXJob29kcyBhcmUgaW4gdGhlIHNhbWUgZ3JvdXAgLSBjYW5ub3QgcGVyZm9ybSBER0UgdGVzdGluZy4gUmV0dXJuaW5nIE5VTEwiKQogICAgICAgICAgICByZXR1cm4oTlVMTCkKICAgICAgICB9CiAgICB9CiAgICAKICAgICMjIEFnZ3JlZ2F0ZSBleHByZXNzaW9uIGJ5IHNhbXBsZQogICAgIyBUbyBhdm9pZCB0cmVhdGluZyBjZWxscyBhcyBpbmRlcGVuZGVudCByZXBsaWNhdGVzCiAgICBpZiAoaXNUUlVFKGFnZ3JlZ2F0ZS5zYW1wbGVzKSkgewogICAgICAgIGZha2UubWV0YVssInNhbXBsZV9pZCJdIDwtIGNvbERhdGEoeClbW3NhbXBsZV9jb2xdXQogICAgICAgIGZha2UubWV0YVssJ3NhbXBsZV9ncm91cCddIDwtIHBhc3RlKGZha2UubWV0YVssInNhbXBsZV9pZCJdLCBmYWtlLm1ldGFbLCJOaG9vZC5Hcm91cCJdLCBzZXA9Il8iKQogICAgICAgIAogICAgICAgIHNhbXBsZV9ncl9tYXQgPC0gbWF0cml4KDAsIG5yb3c9bnJvdyhmYWtlLm1ldGEpLCBuY29sPWxlbmd0aCh1bmlxdWUoZmFrZS5tZXRhJHNhbXBsZV9ncm91cCkpKQogICAgICAgIGNvbG5hbWVzKHNhbXBsZV9ncl9tYXQpIDwtIHVuaXF1ZShmYWtlLm1ldGEkc2FtcGxlX2dyb3VwKQogICAgICAgIHJvd25hbWVzKHNhbXBsZV9ncl9tYXQpIDwtIHJvd25hbWVzKGZha2UubWV0YSkKICAgICAgICAKICAgICAgICBmb3IgKHMgaW4gY29sbmFtZXMoc2FtcGxlX2dyX21hdCkpIHsKICAgICAgICAgICAgc2FtcGxlX2dyX21hdFt3aGljaChmYWtlLm1ldGEkc2FtcGxlX2dyb3VwID09IHMpLHNdIDwtIDEgIAogICAgICAgIH0KICAgICAgICAKICAgICAgICAjIyBTdW1tYXJpc2UgZXhwcmVzc2lvbiBieSBzYW1wbGUKICAgICAgICBleHByc19zbXAgPC0gbWF0cml4KDAsIG5yb3c9bnJvdyhleHBycyksIG5jb2w9bmNvbChzYW1wbGVfZ3JfbWF0KSkKICAgICAgICBpZiAoYXNzYXk9PSdjb3VudHMnKSB7CiAgICAgICAgICAgIHN1bW1GdW5jIDwtIHJvd1N1bXMKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICBzdW1tRnVuYyA8LSByb3dNZWFucwogICAgICAgIH0KICAgICAgICAKICAgICAgICBmb3IgKGkgaW4gMTpuY29sKHNhbXBsZV9ncl9tYXQpKXsKICAgICAgICAgICAgaWYgKHN1bShzYW1wbGVfZ3JfbWF0WyxpXSkgPiAxKSB7CiAgICAgICAgICAgICAgICBleHByc19zbXBbLGldIDwtIHN1bW1GdW5jKGV4cHJzWyx3aGljaChzYW1wbGVfZ3JfbWF0WyxpXSA+IDApXSkgIAogICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgZXhwcnNfc21wWyxpXSA8LSBleHByc1ssd2hpY2goc2FtcGxlX2dyX21hdFssaV0gPiAwKV0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByb3duYW1lcyhleHByc19zbXApIDwtIHJvd25hbWVzKGV4cHJzKQogICAgICAgIGNvbG5hbWVzKGV4cHJzX3NtcCkgPC0gY29sbmFtZXMoc2FtcGxlX2dyX21hdCkKICAgICAgICAKICAgICAgICBzbXBfbWV0YSA8LSBkaXN0aW5jdChmYWtlLm1ldGEsIHNhbXBsZV9ncm91cCwgTmhvb2QuR3JvdXApCiAgICAgICAgcm93bmFtZXMoc21wX21ldGEpIDwtIHNtcF9tZXRhWywic2FtcGxlX2dyb3VwIl0KICAgICAgICAKICAgICAgICBmYWtlLm1ldGEgPC0gc21wX21ldGEKICAgICAgICBleHBycyA8LSBleHByc19zbXAKICAgIH0KICAgIAogICAgCiAgICBmb3IoaSBpbiBzZXFfYWxvbmcobmhvb2QuZ3IpKXsKICAgICAgICBpLm1ldGEgPC0gZmFrZS5tZXRhCiAgICAgICAgaS5tZXRhJFRlc3QgPC0gIlJlZiIKICAgICAgICBpLm1ldGEkVGVzdFtmYWtlLm1ldGEkTmhvb2QuR3JvdXAgPT0gbmhvb2QuZ3JbaV1dIDwtICJUZXN0IgoKICAgICAgICBpZihuY29sKGV4cHJzKSA+IDEgJiBucm93KGkubWV0YSkgPiAxKXsKICAgICAgICAgICAgaS5kZXNpZ24gPC0gYXMuZm9ybXVsYSgiIH4gMCArIFRlc3QiKQogICAgICAgICAgICBpLm1vZGVsIDwtIG1vZGVsLm1hdHJpeChpLmRlc2lnbiwgZGF0YT1pLm1ldGEpCiAgICAgICAgICAgIHJvd25hbWVzKGkubW9kZWwpIDwtIHJvd25hbWVzKGkubWV0YSkKICAgICAgICB9CgogICAgICAgIHNpbmsoZmlsZT0iL2Rldi9udWxsIikKICAgICAgICBnYygpCiAgICAgICAgc2luayhmaWxlPU5VTEwpCgogICAgICAgIGlmKGFzc2F5ID09ICJsb2djb3VudHMiKXsKICAgICAgICAgICAgaS5yZXMgPC0gLnBlcmZvcm1fbG9nbm9ybWFsX2RnZShleHBycywgaS5tb2RlbCwgbW9kZWwuY29udHJhc3RzPWkuY29udHJhc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZS5vZmZzZXQ9Z2VuZS5vZmZzZXQpCiAgICAgICAgfSBlbHNlIGlmKGFzc2F5ID09ICJjb3VudHMiKXsKICAgICAgICAgICAgaS5yZXMgPC0gLnBlcmZvcm1fY291bnRzX2RnZShleHBycywgaS5tb2RlbCwgbW9kZWwuY29udHJhc3RzPWkuY29udHJhc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZS5vZmZzZXQ9Z2VuZS5vZmZzZXQpCiAgICAgICAgICAgIGNvbG5hbWVzKGkucmVzKVtuY29sKGkucmVzKV0gPC0gImFkai5QLlZhbCIKICAgICAgICB9IGVsc2V7CiAgICAgICAgICAgIHdhcm5pbmcoIkFzc2F5IHR5cGUgaXMgbm90IGNvdW50cyBvciBsb2djb3VudHMgLSBhc3N1bWluZyAobG9nKS1ub3JtYWwgZGlzdHJpYnV0aW9uLiBVc2UgdGhlc2UgcmVzdWx0cyBhdCB5b3VyIHBlcmlsIikKICAgICAgICAgICAgaS5yZXMgPC0gLnBlcmZvcm1fbG9nbm9ybWFsX2RnZShleHBycywgaS5tb2RlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5jb250cmFzdHM9aS5jb250cmFzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lLm9mZnNldD1nZW5lLm9mZnNldCkKICAgICAgICB9CgogICAgICAgIGkucmVzJGFkai5QLlZhbFtpcy5uYShpLnJlcyRhZGouUC5WYWwpXSA8LSAxCiAgICAgICAgaS5yZXMkbG9nRkNbaXMuaW5maW5pdGUoaS5yZXMkbG9nRkMpXSA8LSAwCgogICAgICAgIGkucmVzIDwtIGkucmVzWywgYygibG9nRkMiLCAiYWRqLlAuVmFsIildCiAgICAgICAgY29sbmFtZXMoaS5yZXMpIDwtIHBhc3RlKGNvbG5hbWVzKGkucmVzKSwgbmhvb2QuZ3JbaV0sIHNlcD0iXyIpCiAgICAgICAgbWFya2VyLmxpc3RbW3Bhc3RlMChuaG9vZC5ncltpXSldXSA8LSBpLnJlcwogICAgfQoKICAgIG1hcmtlci5kZi5jaG9sIDwtIGRvLmNhbGwoY2JpbmQuZGF0YS5mcmFtZSwgbWFya2VyLmxpc3QpCiAgICBjb2xuYW1lcyhtYXJrZXIuZGYuY2hvbCkgPC0gZ3N1Yihjb2xuYW1lcyhtYXJrZXIuZGYuY2hvbCksIHBhdHRlcm49Il5bMC05XStcXC4iLCByZXBsYWNlbWVudD0iIikKICAgIG1hcmtlci5kZi5jaG9sJEdlbmVJRCA8LSByb3duYW1lcyhpLnJlcykKYGBgCmBgYHtyfQp0YWJsZShuaHMuZGEuZ3IpCmBgYAoKYGBge3J9Cm1hcmtlci5kZi5jaG9sW21hcmtlci5kZi5jaG9sJGFkai5QLlZhbF8xIDwgMC4xLF0KYGBgCgojIyMjIFZpc3VhbGl6ZSBhcyB2b2xjYW5vIAoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp2b2xjYW5vX2Nob2wgPC0gbWFya2VyLmRmLmNob2wgJT4lCiAgbXV0YXRlKGxhYmVsPWlmZWxzZSgoYWRqLlAuVmFsXzEpIDwgMC4xLCBHZW5lSUQsIE5BKSkgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQ18xLCAtbG9nMTAoYWRqLlAuVmFsXzEpLCAKICAgICAgICAgICAgICMgY29sb3I9aGlnaGxpZ2h0CiAgICAgICAgICAgICApKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbD1sYWJlbCksIHNlZ21lbnQuYWxwaGEgPSAwLjMpICsKICB4bGFiKCJsb2dGQyIpICsgeWxhYigiLSBsb2cxMChBZGouIFAgdmFsdWUpIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIyKQoKdm9sY2Fub19jaG9sICAKICAKYGBgCgojIyMjIFZpc3VhbGl6ZSBhcyBoZWF0bWFwIAooZ2VuZSBleHByZXNzaW9uIHZhbHVlcyBhcmUgc2NhbGVkIGJldHdlZW4gMCBhbmQgMSBmb3IgZWFjaCBnZW5lKQoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD05LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptYXJrZXJfZ2VuZXNfY2hvbCA8LSBtYXJrZXIuZGYuY2hvbCAlPiUKICBkcGx5cjo6ZmlsdGVyKGFkai5QLlZhbF8xIDwgMC4xKSAlPiUKICBwdWxsKEdlbmVJRCkKCmhpZ2hsaWdodF9nZW5lcyA8LSBjKCJQTFZBUCIsICJTT1gxNCIsICJWV0ExIiwgIkFDS1IxIiwgIklMMzIiLAogICAgICAgICAgICAgICAgICAgICAiQ0xFQzRHIiwgIkNMRUM0TSIsICJTVEFCMiIsICJNUkMxIiwgIkxZVkUxIiwKICAgICAgICAgICAgICAgICAgICAgIkNEMTQiLCAiU09YMTciLCAiV05UMiIsICJSU1BPMyIsICJBSUYxTCIsCiAgICAgICAgICAgICAgICAgICAgICJQUk9YMSIsICJQRFBOIiwiQ1BFIiwgIkNEMzIwIiwgIkJNUEVSIikKCnBsb3ROaG9vZEV4cHJlc3Npb25EQShsaXZlcl9taWxvLCBtaWxvX3JlcywgbWFya2VyX2dlbmVzX2Nob2wsIGNsdXN0ZXJfZmVhdHVyZXMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xLAogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfdG9fMSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gbWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlPT0iQ2hvbGFuZ2lvY3l0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgaGlnaGxpZ2h0X2ZlYXR1cmVzID0gaGlnaGxpZ2h0X2dlbmVzLCBzaG93X3Jvd25hbWVzID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgKSArCiAgeWxhYigiREUgZ2VuZXMiKSArCiAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjIpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yNCkpICsKICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDEwKSkKCgpgYGAKCgojIyMgR08gdGVybSBhbmFseXNpcwoKYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9Cm1hcmtlcl9nZW5lc19jaG9sIDwtIG1hcmtlci5kZi5jaG9sICU+JQogIGRwbHlyOjpmaWx0ZXIoYWRqLlAuVmFsXzIgPCAwLjEgJiBsb2dGQ18yIDwgMCkgJT4lCiAgcHVsbChHZW5lSUQpCgplbV91cF9jaG9sIDwtIGVucmljaGVyKG1hcmtlcl9nZW5lc19jaG9sLCBURVJNMkdFTkU9bV90MmcsIHBBZGp1c3RNZXRob2QgPSAiZmRyIiwgCiAgICAgICAgICAgICAgICAgIHVuaXZlcnNlID0gcm93bmFtZXMobGl2ZXJfbWlsbykKICAgICAgICAgICAgICAgICAgKQoKZW1fcmVzX3VwX2Nob2wgPC0gZW1fdXBfY2hvbEByZXN1bHRbZW1fdXBfY2hvbEByZXN1bHQkcXZhbHVlIDwgMC4xLF0gJT4lCiAgZHBseXI6OnNlbGVjdCgtIGMoRGVzY3JpcHRpb24pKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ29fY2hvbF91cCA8LSBlbV9yZXNfdXBfY2hvbCAlPiUKICB0b3BfbigyMCwgLWxvZzEwKHF2YWx1ZSkpICU+JQogIG11dGF0ZShUZXJtPWZhY3RvcihJRCwgbGV2ZWxzPXJldih1bmlxdWUoSUQpKSkpICU+JQogIGdncGxvdChhZXMoVGVybSwgLWxvZzEwKHF2YWx1ZSkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBjb29yZF9mbGlwKCkgKwogIHhsYWIoIkdPIEJpb2xvZ2ljYWwgRnVuY3Rpb24iKSArIHlsYWIoIi1sb2cxMChBZGouIHAtdmFsdWUpIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xOCkgKwogIGdndGl0bGUoIkNpcnJob3RpYyBjaG9sYW5naW9jeXRlcyIpCgpnb19jaG9sX3VwCmBgYAoKYGBge3J9CmVtX3Jlc191cF9jaG9sCmBgYAoKCi0tLQoKQXNzZW1ibGUgZmlndXJlCmBgYHtyLCBmaWcuaGVpZ2h0PTI1LCBmaWcud2lkdGg9MTl9CmZpZzRfYm90dG9tIDwtICgoZmlnNF9ibGVmdCArIHBsb3RfbGF5b3V0KCkpIHwKICAgICAgKChmaWc0X2JyaWdodDEgKyBwbG90X2xheW91dCh0YWdfbGV2ZWwgPSAna2VlcCcpKSAvIChmaWc0X2JicmlnaHQgKyBwbG90X2xheW91dCgpKSkgKwogICAgICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDEuNikpCiAgICkgKwogIHBsb3RfbGF5b3V0KHdpZHRocz1jKDEsMS4yKSkKCihmaWc0X3RvcCAvIGZpZzRfYm90dG9tKSArCiAgcGxvdF9sYXlvdXQoaGVpZ2h0cz1jKDEsMS44KSkgICsKICBnZ3NhdmUoIn4vbWlsb19vdXRwdXQvZmlnNC5wZGYiLCBoZWlnaHQgPSAyNiwgd2lkdGggPSAyMiwgdXNlRGluZ2JhdHM9RkFMU0UpCiAgIyBnZ3NhdmUoIn4vbWlsby9tcy9maWd1cmVzL2ZpZ3MvZmlndXJlNS5wZGYiLCBoZWlnaHQgPSAyNiwgd2lkdGggPSAyMiwgdXNlRGluZ2JhdHM9RkFMU0UpCmBgYAoKQXNzZW1ibGUgc3VwcGxlbWVudGFyeSBmaWd1cmUKCmBgYHtyLCBmaWcud2lkdGg9MjUsIGZpZy5oZWlnaHQ9N30KcDEgPC0gcGxvdF9ncmlkKCBnb19lbmRvX3VwKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSkpLCAKICAgICAgICAgICAgICAgICBnb19lbmRvX2Rvd24rIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEpKSwgCiAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDE4LAogICAgICAgICAgICAgICAgIG5jb2w9MSwKICAgICAgICAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMiwyKSwKICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkEiLCAiQiIsIkMiKSkKCnAxCgpjaG9sX2VtYiA8LSAoY2hvbF91bWFwICsgY2hvbF9nciApICsgCiAgcGxvdF9sYXlvdXQod2lkdGhzID0gYygxLDIpLCAKICAgICAgICAgICAgICAgIGd1aWRlcyA9ICJjb2xsZWN0IgogICAgICAgICAgICAgICAgKQoKcDMgPC0gcGxvdF9ncmlkKHBsb3RfZ3JpZChjaG9sX3VtYXAsIGNob2xfZ3IsIG5yb3c9MSxyZWxfd2lkdGhzID0gYygxLDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAxOCwKICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkMiLCJEIikpLAogICAgICAgICAgICAgICAgdm9sY2Fub19jaG9sLAogICAgICAgICAgICAgICAgZ29fY2hvbF91cCArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSksIAogICAgICAgICAgICAgICAgbmNvbD0xLAogICAgICAgICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDEuNSwxLDEuNSksCiAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDE4LAogICAgICAgICAgICAgICAgbGFiZWxzPWMoIiIsIkUiLCdGJykpCgpwbG90X2dyaWQocDEsIHAzLCBuY29sPTIsIHJlbF93aWR0aHMgPSBjKDEsMS4yKSkgKwojIGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSxwMixnb19jaG9sX3VwLCAgcmVsX2hlaWdodHMgPSBjKDEsMS41KSwgbmNvbD0xLCBsYWJlbHMgPSBjKCIiLCAiRiIpKSArCiAgZ2dzYXZlKCJ+L21pbG8vbXMvc3VwcGxlbWVudC9zdXBwbF9maWdzL3N1cHBsX2ZpZzYucGRmIiwgaGVpZ2h0ID0gMTYsIHdpZHRoPTIwKQogIGdnc2F2ZSgifi9taWxvL21zL3N1cHBsZW1lbnQvc3VwcGxfZmlncy9zdXBwbF9maWc2LnBuZyIsIGhlaWdodCA9IDE2LCB3aWR0aD0yMCkKICBnZ3NhdmUoIn4vbWlsb19vdXRwdXQvbGl2ZXJfc3VwcGxlbWVudGFyeS5wbmciLCBoZWlnaHQgPSA3LCB3aWR0aD04KQoKYGBgCgo8IS0tIExldCdzIGNoZWNrIHRoZSBnZW5lcyBpZGVudGlmaWVkIGFzIG1hcmtlcnMgZm9yIHRoZSBkaXNlYXNlIHN1YnR5cGVzLiBBcmUgdGhleSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBiZXR3ZWVuIERBIG5laWdoYm91cmhvb2RzPyBZZXMgdGhleSBhcmUhIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gZGlzZWFzZV9lbmRvX21hcmtlcnMgPC0gYygiQUNLUjEiLCAnQ0QzNCcsIlZXQTEiKSAtLT4KCjwhLS0gZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzIpICU+JSAtLT4KPCEtLSAgIGZpbHRlcihGRFIgPCAwLjA1KSAlPiUgLS0+CjwhLS0gICAuW2Rpc2Vhc2VfZW5kb19tYXJrZXJzLF0gLS0+Cgo8IS0tIGRhdGEuZnJhbWUobWFya2VycyRuZWdMb2dGQ18xKSAlPiUgLS0+CjwhLS0gICBmaWx0ZXIoRkRSIDwgMC4wNSkgJT4lIC0tPgo8IS0tICAgLltkaXNlYXNlX2VuZG9fbWFya2VycyxdIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gVmlzdWFsaXplIHNvbWUgb2YgdGhlIG1hcmtlcnMgdGhhdCBkaWZmZXJlbnRpYXRlIERBIG5laWdoYm91cmhvb2RzLCBieSBwbG90dGluZyB0aGUgcGVyY2VudCBvZiBjZWxscyBleHByZXNzaW5nIGVhY2ggZ2VuZSBpbiBhIG5ob29kLiAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tICMjIERlZmluZSBwbG90dGluZyBmdW5jdGlvbnMgLS0+CjwhLS0gLmNhbGN1bGF0ZV9uaG9vZF9wZXJjX2V4cHJlc3Npb24gPC0gZnVuY3Rpb24obWlsbywgbmhvb2RzLCBnZW5lKXsgLS0+CjwhLS0gICBnZW5lX2NudHMgPC0gY291bnRzKG1pbG8pW2dlbmUsXSAtLT4KPCEtLSAgIHBlcmNfZXhwciA8LSBzYXBwbHkobmhvb2RzKG1pbG8pW25ob29kc10sIGZ1bmN0aW9uKHgpIHN1bShnZW5lX2NudHNbeF0+MCkvbGVuZ3RoKHgpKSAtLT4KPCEtLSAgIHBlcmNfZXhwciA8LSBzZXROYW1lcyhwZXJjX2V4cHIsIG5ob29kcykgLS0+CjwhLS0gICByZXR1cm4ocGVyY19leHByKSAtLT4KPCEtLSAgIH0gLS0+Cgo8IS0tIC5wbG90X25ob29kX2V4cHJlc3Npb24gPC0gZnVuY3Rpb24obWlsbywgbmhvb2RzLCBmZWF0dXJlcyl7IC0tPgo8IS0tICAgcGVyY19leHByX21hdCA8LSBzYXBwbHkoZmVhdHVyZXMsICAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIC5jYWxjdWxhdGVfbmhvb2RfcGVyY19leHByZXNzaW9uKG1pbG8sIG5ob29kcywgeCkpIC0tPgoKPCEtLSAgIHBsX2RmIDwtIGRhdGEuZnJhbWUocGVyY19leHByX21hdCkgJT4lIC0tPgo8IS0tICAgICByb3duYW1lc190b19jb2x1bW4oIk5ob29kIikgJT4lIC0tPgo8IS0tICAgICBtdXRhdGUoTmhvb2Q9YXMuZG91YmxlKE5ob29kKSkgJT4lIC0tPgo8IS0tICAgICBsZWZ0X2pvaW4obWlsb19yZXMpICU+JSAtLT4KPCEtLSAgICAgbXV0YXRlKGxvZ0ZDX3Jhbms9cmFuayhsb2dGQykpICAtLT4KCjwhLS0gICBwbF90b3AgPC0gcGxfZGYgJT4lIC0tPgo8IS0tICAgICAgIG11dGF0ZShpc19zaWduaWYgPSBpZmVsc2UoU3BhdGlhbEZEUiA8IDAuMSwgIlNwYXRpYWxGRFIgPCAwLjEiLCBOQSkpICU+JSAtLT4KPCEtLSAgICAgICBnZ3Bsb3QoYWVzKGxvZ0ZDX3JhbmssIGxvZ0ZDKSkgKyAtLT4KPCEtLSAgICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0yKSArIC0tPgo8IS0tICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjIpICsgLS0+CjwhLS0gICAgICAgZ2VvbV9wb2ludChkYXRhPS4lPiUgZmlsdGVyKCFpcy5uYShpc19zaWduaWYpKSwgYWVzKGNvbG9yPWlzX3NpZ25pZiksIHNpemU9MC41KSArIC0tPgo8IS0tICAgICAgIHRoZW1lX2J3KCkgKyAtLT4KPCEtLSAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSJyZWQiLCBuYW1lPSIiKSArIC0tPgo8IS0tICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgLS0+Cgo8IS0tICAgcGxfYm90dG9tIDwtIHBsX2RmICU+JSAtLT4KPCEtLSAgICAgcGl2b3RfbG9uZ2VyKGNvbHM9ZmVhdHVyZXMsIG5hbWVzX3RvPSdmZWF0dXJlJywgdmFsdWVzX3RvPSJwZXJjX2V4cHJlc3NlZCIpICU+JSAtLT4KPCEtLSAgICAgbXV0YXRlKGZlYXR1cmU9ZmFjdG9yKGZlYXR1cmUsIGxldmVscz1mZWF0dXJlcykpICU+JSAtLT4KPCEtLSAgICAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBmZWF0dXJlLCBmaWxsPXBlcmNfZXhwcmVzc2VkKSkgKyAgLS0+CjwhLS0gICAgIGdlb21fdGlsZSgpICsgLS0+CjwhLS0gICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0ibWFnbWEiKSArIC0tPgo8IS0tICAgICBnZ2Jpbzo6dGhlbWVfY2xlYXIoKSAtLT4KCjwhLS0gICAocGxfdG9wIC8gcGxfYm90dG9tKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMikpIC0tPgo8IS0tIH0gLS0+CjwhLS0gYGBgIC0tPgoKCjwhLS0gYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMn0gLS0+CjwhLS0gZW5kb19uaG9vZHMgPC0gZW5kb19yZXMgJT4lICBwdWxsKE5ob29kKSAtLT4KCjwhLS0gIyMgU2VsZWN0IGdlbmVzIGFuZCBzb3J0IGJ5IEFVQyAtLT4KPCEtLSBmZWF0c19uZWcyIDwtIC0tPgo8IS0tICAgZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzIpICU+JSAgLS0+CjwhLS0gICB0b3Bfbig1MCwgLSBsb2cxMChGRFIpKSAlPiUgLS0+CjwhLS0gICBhcnJhbmdlKEFVQy5wb3NMb2dGQ18xKSAlPiUgLS0+CjwhLS0gICByb3duYW1lcygpIC0tPgoKPCEtLSAucGxvdF9uaG9vZF9leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG9fbmhvb2RzLCBmZWF0dXJlcz1mZWF0cykgLS0+CjwhLS0gYGBgIC0tPgoKPCEtLSBBcyBkZXNjcmliZWQgaW4gdGhlIHBhcGVyLCB3ZSBoYXZlIHRoYXQgZ2VuZXMgYXNzb2NpYXRlZCB3aXRoIGV4dHJhY2VsbHVsYXIgbWF0cml4IG9yZ2FuaXphdGlvbiAoZS5nLiBWSU0sICkgYXJlIG92ZXIgZXhwcmVzc2VkICAtLT4KCgo8IS0tIGBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9N30gLS0+CjwhLS0gIyMgU2VsZWN0IGdlbmVzIGFuZCBzb3J0IGJ5IEFVQyAtLT4KPCEtLSBmZWF0c19uZWcxIDwtIC0tPgo8IS0tICAgZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzEpICU+JSAgLS0+CjwhLS0gICB0b3Bfbig1MCwgLSBsb2cxMChGRFIpKSAlPiUgLS0+CjwhLS0gICBhcnJhbmdlKEFVQy5wb3NMb2dGQ18xKSAlPiUgLS0+CjwhLS0gICByb3duYW1lcygpIC0tPgoKPCEtLSAucGxvdF9uaG9vZF9leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG9fbmhvb2RzLCBmZWF0dXJlcz1mZWF0cykgLS0+Cgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fSAtLT4KPCEtLSBmZWF0c19uZWcxdnNOZWcyIDwtIC0tPgo8IS0tICAgZGF0YS5mcmFtZShtYXJrZXJzJG5lZ0xvZ0ZDXzEpICU+JSAgLS0+CjwhLS0gICB0b3Bfbig1MCwgLSBsb2cxMChGRFIpKSAlPiUgLS0+CjwhLS0gICBhcnJhbmdlKEFVQy5uZWdMb2dGQ18yKSAlPiUgLS0+CjwhLS0gICByb3duYW1lcygpIC0tPgoKPCEtLSAucGxvdF9uaG9vZF9leHByZXNzaW9uKGxpdmVyX21pbG8sIGVuZG9fbmhvb2RzLCBmZWF0dXJlcz1mZWF0c19uZWcxdnNOZWcyKSAtLT4KPCEtLSBgYGAgLS0+CgoKPCEtLSBMb29rIGp1c3QgYXQgRW5kb3RoZWxpYSAoNSkgd2hlcmUgeW91IGhhdmUgYm90aCBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgZm9sZC1jaGFuZ2VzIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gZW5kbzVfbmhvb2RzIDwtIG1pbG9fcmVzICU+JSAgLS0+CjwhLS0gICBmaWx0ZXIoYW5ub3RhdGlvbl9pbmRlcHRoPT0iRW5kb3RoZWxpYSAoNSkiICYgYW5ub3RhdGlvbl9pbmRlcHRoX2ZyYWN0aW9uID4gMC43KSAlPiUgLS0+CjwhLS0gICBwdWxsKE5ob29kKSAtLT4KCjwhLS0gcGVyY19leHByX21hdCA8LSBzYXBwbHkoZmVhdHVyZXMsICAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSAuY2FsY3VsYXRlX25ob29kX3BlcmNfZXhwcmVzc2lvbihsaXZlcl9taWxvLCBlbmRvNV9uaG9vZHMsIHgpKSAtLT4KCjwhLS0gcGxfZGYgPC0gZGF0YS5mcmFtZShwZXJjX2V4cHJfbWF0KSAlPiUgLS0+CjwhLS0gICByb3duYW1lc190b19jb2x1bW4oIk5ob29kIikgJT4lIC0tPgo8IS0tICAgbXV0YXRlKE5ob29kPWFzLmRvdWJsZShOaG9vZCkpICU+JSAtLT4KPCEtLSAgIGxlZnRfam9pbihtaWxvX3JlcykgJT4lIC0tPgo8IS0tICAgbXV0YXRlKGxvZ0ZDX3Jhbms9cmFuayhsb2dGQykpICAtLT4KCjwhLS0gcGxfdG9wIDwtIHBsX2RmICU+JSAtLT4KPCEtLSAgICAgbXV0YXRlKGlzX3NpZ25pZiA9IGlmZWxzZShTcGF0aWFsRkRSIDwgMC4xLCAiU3BhdGlhbEZEUiA8IDAuMSIsIE5BKSkgJT4lIC0tPgo8IS0tICAgICBnZ3Bsb3QoYWVzKGxvZ0ZDX3JhbmssIGxvZ0ZDKSkgKyAtLT4KPCEtLSAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9MikgKyAtLT4KPCEtLSAgICAgZ2VvbV9wb2ludChzaXplPTAuMikgKyAtLT4KPCEtLSAgICAgZ2VvbV9wb2ludChkYXRhPS4lPiUgZmlsdGVyKCFpcy5uYShpc19zaWduaWYpKSwgYWVzKGNvbG9yPWlzX3NpZ25pZiksIHNpemU9MC41KSArIC0tPgo8IS0tICAgICB0aGVtZV9idygpICsgLS0+CjwhLS0gICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9InJlZCIsIG5hbWU9IiIpICsgLS0+CjwhLS0gICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgLS0+Cgo8IS0tIHBsX2JvdHRvbSA8LSBwbF9kZiAlPiUgLS0+CjwhLS0gICBwaXZvdF9sb25nZXIoY29scz1mZWF0dXJlcywgbmFtZXNfdG89J2ZlYXR1cmUnLCB2YWx1ZXNfdG89InBlcmNfZXhwcmVzc2VkIikgJT4lIC0tPgo8IS0tICAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCBmZWF0dXJlLCBmaWxsPXBlcmNfZXhwcmVzc2VkKSkgKyAgLS0+CjwhLS0gICBnZW9tX3RpbGUoKSArIC0tPgo8IS0tICAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uPSJtYWdtYSIpICsgLS0+CjwhLS0gICB0aGVtZV9jbGVhcigpIC0tPgoKPCEtLSAocGxfdG9wIC8gcGxfYm90dG9tKSArIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMikpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gSG93IHRvIGZpbmQgYXNzb2NpYXRpb24gZGUgbm92byBpbiBFbmRvIDU/IC0tPgoKPCEtLSBgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0gLS0+CjwhLS0gIyMgRmluZCBtb3N0IGhpZ2hseSB2YXJpYWJsZSBnZW5lcyBpbiB0aGlzIGNsdXN0ZXIgLS0+CjwhLS0gZW5kbzVfbWlsbyA8LSBsaXZlcl9taWxvWyx3aGljaChjb2xEYXRhKGxpdmVyX21pbG8pW1siYW5ub3RhdGlvbl9pbmRlcHRoIl1dPT0iRW5kb3RoZWxpYSAoNSkiKV0gLS0+CjwhLS0gZGVjX2VuZG81IDwtIG1vZGVsR2VuZVZhcihlbmRvNV9taWxvKSAtLT4KPCEtLSBlbmRvNV9odmdzIDwtIGdldFRvcEhWR3MoZGVjX2VuZG81LCBuPTEwMDApIC0tPgoKPCEtLSBwZXJjX2V4cHJfbWF0IDwtIHNhcHBseShlbmRvNV9odmdzLCBmdW5jdGlvbih4KSAuY2FsY3VsYXRlX25ob29kX3BlcmNfZXhwcmVzc2lvbihsaXZlcl9taWxvLCBlbmRvNV9uaG9vZHMsIHgpKSAtLT4KCjwhLS0gbWlsb19yZXNfZW5kbzUgPC0gbWlsb19yZXNbd2hpY2gobWlsb19yZXMkTmhvb2QgJWluJSBlbmRvNV9uaG9vZHMpLF0gLS0+Cgo8IS0tIGZjX2NvciA8LSBhcHBseShwZXJjX2V4cHJfbWF0LCAyLCBmdW5jdGlvbih4KSBIbWlzYzo6cmNvcnIoeCwgbWlsb19yZXNfZW5kbzUkbG9nRkMpJHJbMSwyXSkgLS0+CjwhLS0gZmNfY29yX3B2YWwgPC0gYXBwbHkocGVyY19leHByX21hdCwgMiwgZnVuY3Rpb24oeCkgSG1pc2M6OnJjb3JyKHgsIG1pbG9fcmVzX2VuZG81JGxvZ0ZDKSRQWzEsMl0pIC0tPgoKPCEtLSBjb3JfZmVhdHMgPC0gbmFtZXMod2hpY2goYWJzKGZjX2NvcikgPiAwLjYgJiBhYnMoZmNfY29yX3B2YWwpIDwgMC4wNSkpIC0tPgo8IS0tIGNvcl9mZWF0c19vcmRlcmVkIDwtIGNvcl9mZWF0c1tvcmRlcihmY19jb3JbY29yX2ZlYXRzXSldIC0tPgoKPCEtLSBwbF9kZiA8LSBkYXRhLmZyYW1lKHBlcmNfZXhwcl9tYXRbLGNvcl9mZWF0c10pICU+JSAtLT4KPCEtLSAgIHJvd25hbWVzX3RvX2NvbHVtbigiTmhvb2QiKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUoTmhvb2Q9YXMuZG91YmxlKE5ob29kKSkgJT4lIC0tPgo8IS0tICAgbGVmdF9qb2luKG1pbG9fcmVzKSAlPiUgLS0+CjwhLS0gICBtdXRhdGUobG9nRkNfcmFuaz1yYW5rKGxvZ0ZDKSkgIC0tPgoKPCEtLSBwbF90b3AgPC0gcGxfZGYgJT4lIC0tPgo8IS0tICAgICBtdXRhdGUoaXNfc2lnbmlmID0gaWZlbHNlKFNwYXRpYWxGRFIgPCAwLjEsICJTcGF0aWFsRkRSIDwgMC4xIiwgTkEpKSAlPiUgLS0+CjwhLS0gICAgIGdncGxvdChhZXMobG9nRkNfcmFuaywgbG9nRkMpKSArIC0tPgo8IS0tICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZT0yKSArIC0tPgo8IS0tICAgICBnZW9tX3BvaW50KHNpemU9MC4yKSArIC0tPgo8IS0tICAgICBnZW9tX3BvaW50KGRhdGE9LiU+JSBmaWx0ZXIoIWlzLm5hKGlzX3NpZ25pZikpLCBhZXMoY29sb3I9aXNfc2lnbmlmKSwgc2l6ZT0wLjUpICsgLS0+CjwhLS0gICAgIHRoZW1lX2J3KCkgKyAtLT4KPCEtLSAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz0icmVkIiwgbmFtZT0iIikgKyAtLT4KPCEtLSAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSAtLT4KCjwhLS0gcGxfYm90dG9tIDwtIHBsX2RmICU+JSAtLT4KPCEtLSAgIHBpdm90X2xvbmdlcihjb2xzPXN0cl9yZXBsYWNlKGNvcl9mZWF0c19vcmRlcmVkLCAiLSIsICIuIiksIG5hbWVzX3RvPSdmZWF0dXJlJywgdmFsdWVzX3RvPSJwZXJjX2V4cHJlc3NlZCIpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShmZWF0dXJlPWZhY3RvcihmZWF0dXJlLCBsZXZlbHM9c3RyX3JlcGxhY2UoY29yX2ZlYXRzX29yZGVyZWQsICItIiwgIi4iKSkpICU+JSAtLT4KPCEtLSAgIGdncGxvdChhZXMobG9nRkNfcmFuaywgZmVhdHVyZSwgZmlsbD1wZXJjX2V4cHJlc3NlZCkpICsgIC0tPgo8IS0tICAgZ2VvbV90aWxlKCkgKyAtLT4KPCEtLSAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0ibWFnbWEiKSArIC0tPgo8IS0tICAgdGhlbWVfY2xlYXIoKSAtLT4KCjwhLS0gKHBsX3RvcCAvIHBsX2JvdHRvbSkgKyBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDIpKSAtLT4KPCEtLSBgYGAgLS0+CgoKCjwhLS0gYGBge3J9IC0tPgo8IS0tICMjIFJ1biBjb21tb24gUENBIC0tPgo8IS0tIG1lcmdlZF9jbnRzIDwtIGNiaW5kKG5ob29kRXhwcmVzc2lvbihlbmRvX21pbG8pLCBsb2djb3VudHMoZW5kb19taWxvKVtodmdzLF0pIC0tPgo8IS0tIG1lcmdlZF9jbnRzX3NjYWxlZCA8LSB0KHNjYWxlKHQobWVyZ2VkX2NudHMpKSkgLS0+CjwhLS0gbWVyZ2VkX3BjYSA8LSBCaW9jU2luZ3VsYXI6OnJ1blBDQSh0KG1lcmdlZF9jbnRzX3NjYWxlZCksIHJhbms9MzAsIGNlbnRlcj1GQUxTRSkgLS0+CjwhLS0gcGNhX21hdCA8LSByYmluZChtZXJnZWRfcGNhJHhbKG5jb2woZW5kb19taWxvKSsxKToobmNvbChlbmRvX21pbG8pKyhsZW5ndGgobmhvb2RzKGVuZG9fbWlsbykpKSksXSwgbWVyZ2VkX3BjYSR4W2NvbG5hbWVzKGVuZG9fbWlsbyksXSkgLS0+CjwhLS0gIyMgQWRkIHRvIHNsb3Qgbmhvb2RzUmVkdWNlZERpbSAtLT4KPCEtLSBuaG9vZFJlZHVjZWREaW0oZW5kb19taWxvLCAiUENBIikgPC0gcGNhX21hdCAtLT4KCjwhLS0gIyMgUnVuIFVNQVAgb24gam9pbnQgUENBIC0tPgo8IS0tIHVtYXBfb3V0IDwtIHV3b3Q6OnVtYXAobmhvb2RSZWR1Y2VkRGltKGVuZG9fbWlsbywgIlBDQSIpLCBuX25laWdoYm9ycyA9IDIwLCBuX2NvbXBvbmVudHMgPSAyLCBzY2FsZT1GQUxTRSkgLS0+CjwhLS0gY29sbmFtZXModW1hcF9vdXQpIDwtIGMoIlVNQVBfMSIsICJVTUFQXzIiKSAtLT4KPCEtLSBuaG9vZFJlZHVjZWREaW0oZW5kb19taWxvLCAiVU1BUCIpIDwtIHVtYXBfb3V0IC0tPgoKPCEtLSBgYGAgLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBzcGxpdF9ieT1OVUxMIC0tPgo8IS0tICMjIEpvaW4gdGVzdCByZXN1bHRzIGFuZCBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb25zIC0tPgo8IS0tIHJkaW1fZGYgPC0gZGF0YS5mcmFtZShuaG9vZFJlZHVjZWREaW0oZW5kb19taWxvLCAiVU1BUCIpWyxjKDEsMildKSAtLT4KPCEtLSBjb2xuYW1lcyhyZGltX2RmKSA8LSBjKCdYJywnWScpIC0tPgoKPCEtLSBuX25ob29kcyA8LSBsZW5ndGgobmhvb2RzKGVuZG9fbWlsbykpIC0tPgo8IS0tIHJkaW1fZGZbLCJOaG9vZCJdIDwtIGlmZWxzZSgxOm5yb3cocmRpbV9kZikgJWluJSBjKDE6bl9uaG9vZHMpLCBjKDE6bl9uaG9vZHMpLCBOQSkgLS0+CjwhLS0gdml6X2RmICA8LSBsZWZ0X2pvaW4ocmRpbV9kZiwgbWlsb19yZXNbd2hpY2gobWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIpLF0sIGJ5PSJOaG9vZCIpIC0tPgo8IS0tIHZpel9kZltbIm5oSW5kZXgiXV0gPC0gdW5saXN0KGlmZWxzZSghaXMubmEodml6X2RmJE5ob29kKSwgbmhvb2RJbmRleChlbmRvX21pbG8pW3Zpel9kZiROaG9vZF0sTkEpKSAtLT4KPCEtLSB2aXpfZGZbaXMubmEodml6X2RmWyJuaEluZGV4Il0pLCduaEluZGV4J10gPC0gMTpuY29sKGVuZG9fbWlsbykgIyBBZGQgaW5kZXggYWxzbyB0byBzaW5nbGUtY2VsbHMgLS0+Cgo8IS0tIGlmICghaXMubnVsbChzcGxpdF9ieSkpeyAtLT4KPCEtLSAgIHNwbGl0X2RmIDwtIGRhdGEuZnJhbWUoc3BsaXRfYnk9Y29sRGF0YShlbmRvX21pbG8pWyxzcGxpdF9ieV0pIC0tPgo8IS0tICAgc3BsaXRfZGZbLCJuaEluZGV4Il0gPC0gMTpucm93KHNwbGl0X2RmKSAtLT4KPCEtLSAgIHZpel9kZiAgPC0gbGVmdF9qb2luKHZpel9kZiwgc3BsaXRfZGYsIGJ5PSJuaEluZGV4IikgLS0+CjwhLS0gfSAtLT4KCjwhLS0gZmlsdGVyX2FscGhhPTAuMSAtLT4KPCEtLSAjIyBGaWx0ZXIgc2lnbmlmaWNhbnQgREEgbmhvb2RzIC0tPgo8IS0tIGlmICghaXMubnVsbChmaWx0ZXJfYWxwaGEpKSB7IC0tPgo8IS0tICAgaWYgKGZpbHRlcl9hbHBoYSA+IDApIHsgLS0+CjwhLS0gICAgIHZpel9kZiA8LSBtdXRhdGUodml6X2RmLCBsb2dGQyA9IGlmZWxzZShTcGF0aWFsRkRSID4gZmlsdGVyX2FscGhhLCBOQSwgbG9nRkMpKSAtLT4KPCEtLSAgIH0gLS0+CjwhLS0gfSAtLT4KCjwhLS0gIyMgUGxvdCAtLT4KPCEtLSBwdF9zaXplPTEgLS0+CjwhLS0gbmhvb2RfcmVkdWNlZF9kaW1zPSJVTUFQIiAtLT4KPCEtLSBjb21wb25lbnRzPWMoMSwyKSAtLT4KPCEtLSAgIHBsIDwtIC0tPgo8IS0tICAgICBnZ3Bsb3QoZGF0YSA9IGFycmFuZ2Uodml6X2RmLCBhYnMobG9nRkMpKSwgLS0+CjwhLS0gICAgICAgICAgICBhZXMoWCwgWSkpICsgLS0+CjwhLS0gICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gJycpLCBzaXplID0gcHRfc2l6ZSAvIDMsIGFscGhhID0gMC41KSArIC0tPgo8IS0tICAgICBnZW9tX3BvaW50KCAtLT4KPCEtLSAgICAgICBkYXRhID0gLiAlPiUgZmlsdGVyKCFpcy5uYShTcGF0aWFsRkRSKSksIC0tPgo8IS0tICAgICAgIGFlcyhmaWxsID0gbG9nRkMpLCAtLT4KPCEtLSAgICAgICBzaXplID0gcHRfc2l6ZSwgLS0+CjwhLS0gICAgICAgc3Ryb2tlID0gMC4xLCAtLT4KPCEtLSAgICAgICAjIGNvbG91cj0iYmxhY2siLCAtLT4KPCEtLSAgICAgICBzaGFwZSA9IDIxIC0tPgo8IS0tICAgICApICsgLS0+CjwhLS0gICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKCAtLT4KPCEtLSAgICAgICBtaWRwb2ludCA9IDAsIC0tPgo8IS0tICAgICAgIGhpZ2ggPSAicmVkIiwgLS0+CjwhLS0gICAgICAgbG93ID0gImJsdWUiLCAtLT4KPCEtLSAgICAgICBuYW1lID0gImxvZy1GQyIgLS0+CjwhLS0gICAgICkgKyAtLT4KPCEtLSAgICAgeGxhYihwYXN0ZShuaG9vZF9yZWR1Y2VkX2RpbXMsIGNvbXBvbmVudHNbMV0sIHNlcD0iXyIpKSArIC0tPgo8IS0tICAgICB5bGFiKHBhc3RlKG5ob29kX3JlZHVjZWRfZGltcywgY29tcG9uZW50c1syXSwgc2VwPSJfIikpIC0tPgoKPCEtLSAgIGlmICghaXMubnVsbChzcGxpdF9ieSkpIHsgLS0+CjwhLS0gICAgIHBsIDwtIHBsICsgZmFjZXRfd3JhcChzcGxpdF9ieX4uKSAtLT4KPCEtLSAgIH0gLS0+CjwhLS0gICBpZiAoIWlzLm51bGwoZmlsdGVyX2FscGhhKSkgeyAtLT4KPCEtLSAgICAgcGwgPC0gcGwgKyAtLT4KPCEtLSAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gJ2dyZXknLCBsYWJlbCA9IHBhc3RlKCJTcGF0aWFsRkRSID4iLCByb3VuZChmaWx0ZXJfYWxwaGEsIDIpKSkgKyAtLT4KPCEtLSAgICAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKCAtLT4KPCEtLSAgICAgICAgICcnLCAtLT4KPCEtLSAgICAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoIC0tPgo8IS0tICAgICAgICAgICBzaGFwZSA9IDIxLCAtLT4KPCEtLSAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwgLS0+CjwhLS0gICAgICAgICAgIGZpbGwgPSAiZ3JleTUwIiwgLS0+CjwhLS0gICAgICAgICAgIHNpemUgPSBwdF9zaXplLCAtLT4KPCEtLSAgICAgICAgICAgYWxwaGEgPSAxLCAtLT4KPCEtLSAgICAgICAgICAgc3Ryb2tlID0gMC4xIC0tPgo8IS0tICAgICAgICAgKSAtLT4KPCEtLSAgICAgICApKSAtLT4KPCEtLSAgIH0gZWxzZSB7IC0tPgo8IS0tICAgICBwbCA8LSBwbCArIC0tPgo8IS0tICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSAnZ3JleScpICsgLS0+CjwhLS0gICAgICAgZ3VpZGVzKGNvbG9yPSJub25lIikgLS0+CjwhLS0gICB9IC0tPgoKPCEtLSAgIHBsIDwtIHBsICsgLS0+CjwhLS0gICAgIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTYpICsgLS0+CjwhLS0gICAgIHRoZW1lKCAtLT4KPCEtLSAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCAtLT4KPCEtLSAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIC0tPgo8IS0tICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpIC0tPgo8IS0tICAgICApIC0tPgo8IS0tIHBsIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIGVuZG9fbWlsbyA8LSBzY2F0ZXI6OnJ1blBDQShlbmRvX21pbG8sIHN1YnNldF9yb3c9aHZncykgLS0+CjwhLS0gYGBgIC0tPgoKCgo8IS0tIC0tLSAtLT4KPCEtLSAjIyBPbGQgKGJlZm9yZSBJIGdvdCBkYXRhc2V0IGZyb20gYXV0aG9ycykgLS0+Cgo8IS0tIFVzaW5nIGRhdGEgZnJvbSBbUmFtYWNoYW5kcmFuIGV0IGFsLiAyMDE5XShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL3M0MTU4Ni0wMTktMTYzMS0zI1NlYzEpIChHRU8gYWNjZXNzaWlvbjogR1NFMTM2MTAzKS4gIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gaHVtYW5fZmlsZXMgPC0gbGlzdC5maWxlcygifi9Eb3dubG9hZHMvR1NFMTM2MTAzX1JBVyIsIHBhdHRlcm49IkdTTTQwNDExLi5faGVhbHRoeXxjaXJyaG90aWMiLCBmdWxsLm5hbWVzID0gVFJVRSkgIC0tPgoKPCEtLSBwcmVmaXhlcyA8LSBzdHJfcmVtb3ZlKGh1bWFuX2ZpbGVzLCAiYmFyY29kZXMudHN2Lmd6fGdlbmVzLnRzdi5nenxtYXRyaXgubXR4Lmd6IikgJT4lIC0tPgo8IS0tICAgIyBzdHJfcmVtb3ZlKCIuKy8iKSAlPiUgLS0+CjwhLS0gICB1bmlxdWUoKSAgLS0+Cgo8IS0tIHNjZV9scyA8LSBsYXBwbHkocHJlZml4ZXMsIGZ1bmN0aW9uKHgpIHJlYWQxMHhDb3VudHMoeCwgdHlwZT0icHJlZml4IikpIC0tPgo8IS0tIGxpdmVyX3NjZSA8LSBwdXJycjo6cmVkdWNlKHNjZV9scywgY2JpbmQpIC0tPgoKPCEtLSAjIyBNYWtlIGNvbERhdGEgaW5mbyAtLT4KPCEtLSBuZXdfY29sZGF0YSA8LSBjb2xEYXRhKGxpdmVyX3NjZSkgJT4lIC0tPgo8IS0tICAgZGF0YS5mcmFtZSgpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShTYW1wbGU9c3RyX3JlbW92ZShTYW1wbGUsICIuKy8iKSAlPiUgc3RyX3JlbW92ZSgiXyQiKSkgJT4lIC0tPgo8IS0tICAgc2VwYXJhdGUoU2FtcGxlLCBpbnRvPWMoImNvbDEiLCAiUGF0aWVudCIsICJTb3J0IiksIHNlcCA9ICJfIiwgcmVtb3ZlPUZBTFNFKSAlPiUgIC0tPgo8IS0tICAgbXV0YXRlKENvbmRpdGlvbj1zdHJfcmVtb3ZlKFBhdGllbnQsICIuJCIpKSAlPiUgLS0+CjwhLS0gICBzZWxlY3QoLWNvbDEpICU+JSAtLT4KPCEtLSAgIG11dGF0ZShDZWxsX2lkID0gc3RyX2MoU2FtcGxlLCAiXyIsQmFyY29kZSkpICU+JSAtLT4KPCEtLSAgIGNvbHVtbl90b19yb3duYW1lcygiQ2VsbF9pZCIpIC0tPgoKPCEtLSBjb2xuYW1lcyhsaXZlcl9zY2UpIDwtIHJvd25hbWVzKG5ld19jb2xkYXRhKSAtLT4KPCEtLSBjb2xEYXRhKGxpdmVyX3NjZSkgPC0gRGF0YUZyYW1lKG5ld19jb2xkYXRhKSAtLT4KCjwhLS0gIyBzYXZlUkRTKGxpdmVyX3NjZSwgIn4vR1NFMTM2MTAzX1NpbmdsZUNlbGxFeHBlcmltZW50LlJEUyIpIC0tPgo8IS0tIGBgYCAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gbGl2ZXJfc2NlIDwtIHJlYWRSRFMoIn4vR1NFMTM2MTAzX1NpbmdsZUNlbGxFeHBlcmltZW50LlJEUyIpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gUUMgbWV0cmljcyBzaG93IHRoYXQgdGhlIG91dGxpZXIgY2VsbHMgYXJlIGFscmVhZHkgZmlsdGVyZWQgKGZvbGxvd2luZyBbdGhpc10oaHR0cHM6Ly9vc2NhLmJpb2NvbmR1Y3Rvci5vcmcvb3ZlcnZpZXcuaHRtbCNkYXRhLXByb2Nlc3NpbmctYW5kLWRvd25zdHJlYW0tYW5hbHlzaXMpKSAtLT4KCjwhLS0gYGBge3IsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTh9IC0tPgo8IS0tICMgaXMubWl0byA8LSBncmVwbCgiXk1ULSIsIHJvd25hbWVzKGxpdmVyX3NjZSkpIC0tPgo8IS0tIHFjc3RhdHMgPC0gcGVyQ2VsbFFDTWV0cmljcyhsaXZlcl9zY2UpIC0tPgoKPCEtLSBjb2xEYXRhKGxpdmVyX3NjZSkgPC0gY2JpbmQoY29sRGF0YShsaXZlcl9zY2UpLCBxY3N0YXRzKSAtLT4KCjwhLS0gcGxvdENvbERhdGEobGl2ZXJfc2NlLCB4PSJTYW1wbGUiLCB5ID0gInRvdGFsIiwgb3RoZXJfZmllbGRzID0gIkNvbmRpdGlvbiIpICsgLS0+CjwhLS0gICBzY2FsZV95X2xvZzEwKCkgKyAtLT4KPCEtLSAgIGZhY2V0X3dyYXAofkNvbmRpdGlvbiwgc2NhbGVzID0gImZyZWUiKSArIC0tPgo8IS0tICAgZ2d0aXRsZSgidG90YWwgY291bnRzIikgIC0tPgoKPCEtLSBwbG90Q29sRGF0YShsaXZlcl9zY2UsIHg9IlNhbXBsZSIsIHkgPSAiZGV0ZWN0ZWQiLCBvdGhlcl9maWVsZHMgPSAiQ29uZGl0aW9uIikgKyAtLT4KPCEtLSAgIGZhY2V0X3dyYXAofkNvbmRpdGlvbiwgc2NhbGVzID0gImZyZWUiKSArIC0tPgo8IS0tICAgZ2d0aXRsZSgiRGV0ZWN0ZWQgZ2VuZXMiKSAgLS0+Cgo8IS0tIGBgYCAtLT4KCjwhLS0gIyMjIE5vcm1hbGl6YXRpb24gLS0+Cgo8IS0tIGBgYHtyfSAtLT4KPCEtLSBsaWJfc2YgPC0gbGlicmFyeVNpemVGYWN0b3JzKGxpdmVyX3NjZSkgLS0+CjwhLS0gaGlzdChsb2cxMChsaWJfc2YpLCB4bGFiPSJMb2cxMFtTaXplIGZhY3Rvcl0iLCBjb2w9J2dyZXk4MCcpIC0tPgo8IS0tIGBgYCAtLT4KPCEtLSBgYGB7cn0gLS0+CjwhLS0gc2V0LnNlZWQoMTAwKSAtLT4KPCEtLSBsaXZlcl9zY2UgPC0gbG9nTm9ybUNvdW50cyhsaXZlcl9zY2UpIC0tPgo8IS0tIGFzc2F5TmFtZXMobGl2ZXJfc2NlKSAtLT4KPCEtLSBgYGAgLS0+Cgo8IS0tICMjIyBGZWF0dXJlIHNlbGVjdGlvbiAtLT4KCjwhLS0gYGBge3J9IC0tPgo8IS0tIGxpYnJhcnkoc2NyYW4pIC0tPgo8IS0tIGRlY19saXZlciA8LSBtb2RlbEdlbmVWYXIobGl2ZXJfc2NlKSAtLT4KCjwhLS0gIyBWaXN1YWxpemluZyB0aGUgZml0OiAtLT4KPCEtLSBmaXRfbGl2ZXIgPC0gbWV0YWRhdGEoZGVjX2xpdmVyKSAtLT4KPCEtLSBwbG90KGZpdF9saXZlciRtZWFuLCBmaXRfbGl2ZXIkdmFyLCB4bGFiPSJNZWFuIG9mIGxvZy1leHByZXNzaW9uIiwgLS0+CjwhLS0gICAgIHlsYWI9IlZhcmlhbmNlIG9mIGxvZy1leHByZXNzaW9uIikgLS0+Cgo8IS0tIGh2Z3MgPC0gZ2V0VG9wSFZHcyhkZWNfbGl2ZXIsIG49MzAwMCkgLS0+CjwhLS0gYGBgIC0tPgoKCgo8IS0tICMjIyBEaW0gcmVkdWN0aW9uIC0tPgoKPCEtLSBgYGB7ciwgZmlnLmhlaWdodD0xNCwgZmlnLndpZHRoPTE0fSAtLT4KPCEtLSBsaXZlcl9zY2UgPC0gc2NhdGVyOjpydW5QQ0EobGl2ZXJfc2NlLCBzdWJzZXRfcm93PWh2Z3MsIG5jb21wb25lbnRzPTMwKSAtLT4KPCEtLSByZWR1Y2VkRGltKGxpdmVyX3NjZSwgIlBDQSIpIDwtIHJlZHVjZWREaW0obGl2ZXJfc2NlLCAiUENBIilbLDE6MTFdIC0tPgo8IS0tIHBsb3RQQ0EobGl2ZXJfc2NlLCBjb2xvdXJfYnk9IkNvbmRpdGlvbiIsIG5jb21wb25lbnRzPTMpIC0tPgo8IS0tIGBgYCAtLT4KCjwhLS0gYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9IC0tPgo8IS0tIGxpdmVyX3NjZSA8LSBydW5VTUFQKGxpdmVyX3NjZSwgZGltcmVkPSJQQ0EiLCBuY29tcG9uZW50cz0yKSAtLT4KCjwhLS0gc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iQ29uZGl0aW9uIiwgcG9pbnRfYWxwaGE9MSwgIHBvaW50X3NpemU9MC44KSAgLS0+CjwhLS0gc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iU29ydCIsIHBvaW50X2FscGhhPTAuMywgIHBvaW50X3NpemU9MC41KSAtLT4KPCEtLSBzY2F0ZXI6OnBsb3RVTUFQKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJQYXRpZW50IiwgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUpIC0tPgo8IS0tIGBgYCAtLT4KPCEtLSBgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfSAtLT4KPCEtLSByb3duYW1lcyhsaXZlcl9zY2UpIDwtIHJvd0RhdGEobGl2ZXJfc2NlKSRTeW1ib2wgLS0+CjwhLS0gc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iQ0QzRCIsIHBvaW50X2FscGhhPTAuMywgcG9pbnRfc2l6ZT0wLjUpIC0tPgo8IS0tIGBgYCAtLT4KCgoK